使用以下技术:
- Spring 4.1.7.RELEASE
- Hibernate Core 4.3.10.Final
- validation-api 1.1.0.Final
- hibernate-validator 5.1.3.Final
- MySQL Server 5.6
- Maven 3
- JDK 1.7
- Tomcat 8.0.21
- Eclipse JUNO Service Release 2
现在,让我们开始!
步骤1.创建模式用于连接多对多表关联
APP_USER%uA0:包含用户。一个用户可以有多个配置[USER,ADMIN,DBA]。
USER_PROFILE%uA0:%uA0包含用户配置文件。配置文件可以链接到多个用户。
APP_USER_USER_PROFILE%uA0:%uA0这是一个连接表连接APP_USER&USER_PROFILE中的多对多关系。
create table APP_USER ( id BIGINT NOT NULL AUTO_INCREMENT, sso_id VARCHAR(30) NOT NULL, password VARCHAR(100) NOT NULL, first_name VARCHAR(30) NOT NULL, last_name VARCHAR(30) NOT NULL, email VARCHAR(30) NOT NULL, PRIMARY KEY (id), UNIQUE (sso_id) ) create table USER_PROFILE( id BIGINT NOT NULL AUTO_INCREMENT, type VARCHAR(30) NOT NULL, PRIMARY KEY (id), UNIQUE (type) ) CREATE TABLE APP_USER_USER_PROFILE ( user_id BIGINT NOT NULL, user_profile_id BIGINT NOT NULL, PRIMARY KEY (user_id, user_profile_id), CONSTRAINT FK_APP_USER FOREIGN KEY (user_id) REFERENCES APP_USER (id), CONSTRAINT FK_USER_PROFILE FOREIGN KEY (user_profile_id) REFERENCES USER_PROFILE (id) ) /* Populate USER_PROFILE Table */ INSERT INTO USER_PROFILE(type) VALUES (&aposUSER&apos) INSERT INTO USER_PROFILE(type) VALUES (&aposADMIN&apos) INSERT INTO USER_PROFILE(type) VALUES (&aposDBA&apos) commit
第2步:创建目录结构
第3步:更新pom.xml,包括所需的依赖关系
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <groupId>com.yiibai.springmvc</groupId> <artifactId>SpringMVCMany2ManyCRUD</artifactId> <packaging>war</packaging> <version>1.0.0</version> <name>SpringMVCHibernateManyToManyCRUDExample</name> <properties> <springframework.version>4.1.7.RELEASE</springframework.version> <hibernate.version>4.3.10.Final</hibernate.version> <mysql.connector.version>5.1.31</mysql.connector.version> </properties> <dependencies> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${springframework.version}</version> </dependency> <!-- Hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <!-- jsr303 validation --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.1.3.Final</version> </dependency> <!-- MySQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.connector.version}</version> </dependency> <!-- Servlet+JSP+JSTL --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.4</version> <configuration> <warSourceDirectory>src/main/webapp</warSourceDirectory> <warName>SpringMVCMany2ManyCRUD</warName> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </pluginManagement> <finalName>SpringMVCMany2ManyCRUD</finalName> </build> </project>
第4步:准备Model类
package com.yiibai.springmvc.model import java.util.HashSet import java.util.Set import javax.persistence.Column import javax.persistence.Entity import javax.persistence.FetchType import javax.persistence.GeneratedValue import javax.persistence.GenerationType import javax.persistence.Id import javax.persistence.JoinColumn import javax.persistence.JoinTable import javax.persistence.ManyToMany import javax.persistence.Table import org.hibernate.validator.constraints.NotEmpty @Entity @Table(name="APP_USER") public class User { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id @NotEmpty @Column(name="SSO_ID", unique=true, nullable=false) private String ssoId @NotEmpty @Column(name="PASSWORD", nullable=false) private String password @NotEmpty @Column(name="FIRST_NAME", nullable=false) private String firstName @NotEmpty @Column(name="LAST_NAME", nullable=false) private String lastName @NotEmpty @Column(name="EMAIL", nullable=false) private String email @NotEmpty @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "APP_USER_USER_PROFILE", joinColumns = { @JoinColumn(name = "USER_ID") }, inverseJoinColumns = { @JoinColumn(name = "USER_PROFILE_ID") }) private Set<UserProfile> userProfiles = new HashSet<UserProfile>() public Integer getId() { return id } public void setId(Integer id) { this.id = id } public String getSsoId() { return ssoId } public void setSsoId(String ssoId) { this.ssoId = ssoId } public String getPassword() { return password } public void setPassword(String password) { this.password = password } public String getFirstName() { return firstName } public void setFirstName(String firstName) { this.firstName = firstName } public String getLastName() { return lastName } public void setLastName(String lastName) { this.lastName = lastName } public String getEmail() { return email } public void setEmail(String email) { this.email = email } public Set<UserProfile> getUserProfiles() { return userProfiles } public void setUserProfiles(Set<UserProfile> userProfiles) { this.userProfiles = userProfiles } @Override public int hashCode() { final int prime = 31 int result = 1 result = prime * result + ((id == null) ? 0 : id.hashCode()) result = prime * result + ((ssoId == null) ? 0 : ssoId.hashCode()) return result } @Override public boolean equals(Object obj) { if (this == obj) return true if (obj == null) return false if (!(obj instanceof User)) return false User other = (User) obj if (id == null) { if (other.id != null) return false } else if (!id.equals(other.id)) return false if (ssoId == null) { if (other.ssoId != null) return false } else if (!ssoId.equals(other.ssoId)) return false return true } @Override public String toString() { return "User [id=" + id + ", ssoId=" + ssoId + ", password=" + password + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + "]" } }
@ManyToMany表示用户和用户配置之间有多到多关系。一个用户可以有多个资料[USER,ADMIN,DBA]用户资料信息可以属于多个用户。@JoinTable表示它使用两个表的表外键链接来约束自己的主键。这个注解,主要用于关系的拥有方。joinColumns是指拥有方(用户ID)的列名,inverseJoinColumns是指关系的反向端(USER_PROFILE的ID)的列。这个连接表的主键是USER_ID%uA0&%uA0USER_PROFILE_ID%uA0组合。
要特别注意fetch%uA0=ꃾtchType.LAZY。在这里,我们通知%uA0Hibernate%uA0懒加载用户资料集合。%uA0这也是默认的行为。在此设置中,首先访问仅当查询加载集合将被触发。这是一个很好的方式,以避免加载-这是一个昂贵的操作所有连接的对象。%uA0当在事务/活动会话,并会尝试访问集合,Hibernate会触发不同的选择来获取它们。
但是,如果您不在活动的会话(会话关闭/无事务:如在JSP),并试图访问集合,你会遇到报应:org.hibernate.LazyInitializationException – could not initialize proxy – no Session.%uA0为了避免它,需要通过调用 Hibernate.initialize(user.getUserProfiles())%uA0来初始化对需要的集合%uA0在有效会话中[在DAO方法,在显示视图之前,可以调用这个初始化方法]。
package com.yiibai.springmvc.model import javax.persistence.Column import javax.persistence.Entity import javax.persistence.GeneratedValue import javax.persistence.GenerationType import javax.persistence.Id import javax.persistence.Table @Entity @Table(name="USER_PROFILE") public class UserProfile { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id @Column(name="TYPE", length=15, unique=true, nullable=false) private String type = UserProfileType.USER.getUserProfileType() public Integer getId() { return id } public void setId(Integer id) { this.id = id } public String getType() { return type } public void setType(String type) { this.type = type } @Override public int hashCode() { final int prime = 31 int result = 1 result = prime * result + ((id == null) ? 0 : id.hashCode()) result = prime * result + ((type == null) ? 0 : type.hashCode()) return result } @Override public boolean equals(Object obj) { if (this == obj) return true if (obj == null) return false if (!(obj instanceof UserProfile)) return false UserProfile other = (UserProfile) obj if (id == null) { if (other.id != null) return false } else if (!id.equals(other.id)) return false if (type == null) { if (other.type != null) return false } else if (!type.equals(other.type)) return false return true } @Override public String toString() { return "UserProfile [id=" + id + ", type=" + type + "]" } }
package com.yiibai.springmvc.model public enum UserProfileType { USER("USER"), DBA("DBA"), ADMIN("ADMIN") String userProfileType private UserProfileType(String userProfileType){ this.userProfileType = userProfileType } public String getUserProfileType(){ return userProfileType } }
第5步:创建DAO层
package com.yiibai.springmvc.dao import java.util.List import com.yiibai.springmvc.model.User public interface UserDao { User findById(int id) User findBySSO(String sso) void save(User user) void deleteBySSO(String sso) List<User> findAllUsers() }
package com.yiibai.springmvc.dao import java.util.List import com.yiibai.springmvc.model.UserProfile public interface UserProfileDao { List<UserProfile> findAll() UserProfile findByType(String type) UserProfile findById(int id) }
package com.yiibai.springmvc.dao import java.io.Serializable import java.lang.reflect.ParameterizedType import org.hibernate.Criteria import org.hibernate.Session import org.hibernate.SessionFactory import org.springframework.beans.factory.annotation.Autowired public abstract class AbstractDao<PK extends Serializable, T> { private final Class<T> persistentClass @SuppressWarnings("unchecked") public AbstractDao(){ this.persistentClass =(Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass ()).getActualTypeArguments()[1] } @Autowired private SessionFactory sessionFactory protected Session getSession(){ return sessionFactory.getCurrentSession() } @SuppressWarnings("unchecked") public T getByKey(PK key) { return (T) getSession().get(persistentClass, key) } public void persist(T entity) { getSession().persist(entity) } public void delete(T entity) { getSession().delete(entity) } protected Criteria createEntityCriteria(){ return getSession().createCriteria(persistentClass) } }
package com.yiibai.springmvc.dao import java.util.List import org.hibernate.Criteria import org.hibernate.Hibernate import org.hibernate.criterion.Order import org.hibernate.criterion.Restrictions import org.springframework.stereotype.Repository import com.yiibai.springmvc.model.User @Repository("userDao") public class UserDaoImpl extends AbstractDao<Integer, User> implements UserDao { public User findById(int id) { User user = getByKey(id) if(user!=null){ Hibernate.initialize(user.getUserProfiles()) } return user } public User findBySSO(String sso) { System.out.println("SSO : "+sso) Criteria crit = createEntityCriteria() crit.add(Restrictions.eq("ssoId", sso)) User user = (User)crit.uniqueResult() if(user!=null){ Hibernate.initialize(user.getUserProfiles()) } return user } @SuppressWarnings("unchecked") public List<User> findAllUsers() { Criteria criteria = createEntityCriteria().addOrder(Order.asc("firstName")) criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)//To avoid duplicates. List<User> users = (List<User>) criteria.list() // No need to fetch userProfiles since we are not showing them on list page. Let them lazy load. // Uncomment below lines for eagerly fetching of userProfiles if you want. /* for(User user : users){ Hibernate.initialize(user.getUserProfiles()) }*/ return users } public void save(User user) { persist(user) } public void deleteBySSO(String sso) { Criteria crit = createEntityCriteria() crit.add(Restrictions.eq("ssoId", sso)) User user = (User)crit.uniqueResult() delete(user) } }
package com.yiibai.springmvc.dao import java.util.List import org.hibernate.Criteria import org.hibernate.criterion.Order import org.hibernate.criterion.Restrictions import org.springframework.stereotype.Repository import com.yiibai.springmvc.model.UserProfile @Repository("userProfileDao") public class UserProfileDaoImpl extends AbstractDao<Integer, UserProfile>implements UserProfileDao{ public UserProfile findById(int id) { return getByKey(id) } public UserProfile findByType(String type) { Criteria crit = createEntityCriteria() crit.add(Restrictions.eq("type", type)) return (UserProfile) crit.uniqueResult() } @SuppressWarnings("unchecked") public List<UserProfile> findAll(){ Criteria crit = createEntityCriteria() crit.addOrder(Order.asc("type")) return (List<UserProfile>)crit.list() } }
第6步:创建服务层
package com.yiibai.springmvc.service import java.util.List import com.yiibai.springmvc.model.UserProfile public interface UserProfileService { UserProfile findById(int id) UserProfile findByType(String type) List<UserProfile> findAll() }
package com.yiibai.springmvc.service import java.util.List import com.yiibai.springmvc.model.User public interface UserService { User findById(int id) User findBySSO(String sso) void saveUser(User user) void updateUser(User user) void deleteUserBySSO(String sso) List<User> findAllUsers() boolean isUserSSOUnique(Integer id, String sso) }
package com.yiibai.springmvc.service import java.util.List import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import com.yiibai.springmvc.dao.UserProfileDao import com.yiibai.springmvc.model.UserProfile @Service("userProfileService") @Transactional public class UserProfileServiceImpl implements UserProfileService{ @Autowired UserProfileDao dao public UserProfile findById(int id) { return dao.findById(id) } public UserProfile findByType(String type){ return dao.findByType(type) } public List<UserProfile> findAll() { return dao.findAll() } }
package com.yiibai.springmvc.service import java.util.List import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import com.yiibai.springmvc.dao.UserDao import com.yiibai.springmvc.model.User @Service("userService") @Transactional public class UserServiceImpl implements UserService{ @Autowired private UserDao dao public User findById(int id) { return dao.findById(id) } public User findBySSO(String sso) { User user = dao.findBySSO(sso) return user } public void saveUser(User user) { dao.save(user) } /* * Since the method is running with Transaction, No need to call hibernate update explicitly. * Just fetch the entity from db and update it with proper values within transaction. * It will be updated in db once transaction ends. */ public void updateUser(User user) { User entity = dao.findById(user.getId()) if(entity!=null){ entity.setSsoId(user.getSsoId()) entity.setPassword(user.getPassword()) entity.setFirstName(user.getFirstName()) entity.setLastName(user.getLastName()) entity.setEmail(user.getEmail()) entity.setUserProfiles(user.getUserProfiles()) } } public void deleteUserBySSO(String sso) { dao.deleteBySSO(sso) } public List<User> findAllUsers() { return dao.findAllUsers() } public boolean isUserSSOUnique(Integer id, String sso) { User user = findBySSO(sso) return ( user == null || ((id != null) && (user.getId() == id))) } }
第7步:创建Hibernate配置
package com.yiibai.springmvc.configuration import java.util.Properties import javax.sql.DataSource import org.hibernate.SessionFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Bean import org.springframework.context.annotation.ComponentScan import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.PropertySource import org.springframework.core.env.Environment import org.springframework.jdbc.datasource.DriverManagerDataSource import org.springframework.orm.hibernate4.HibernateTransactionManager import org.springframework.orm.hibernate4.LocalSessionFactoryBean import org.springframework.transaction.annotation.EnableTransactionManagement @Configuration @EnableTransactionManagement @ComponentScan({ "com.yiibai.springmvc.configuration" }) @PropertySource(value = { "classpath:application.properties" }) public class HibernateConfiguration { @Autowired private Environment environment @Bean public LocalSessionFactoryBean sessionFactory() { LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean() sessionFactory.setDataSource(dataSource()) sessionFactory.setPackagesToScan(new String[] { "com.yiibai.springmvc.model" }) sessionFactory.setHibernateProperties(hibernateProperties()) return sessionFactory } @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource() dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName")) dataSource.setUrl(environment.getRequiredProperty("jdbc.url")) dataSource.setUsername(environment.getRequiredProperty("jdbc.username")) dataSource.setPassword(environment.getRequiredProperty("jdbc.password")) return dataSource } private Properties hibernateProperties() { Properties properties = new Properties() properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect")) properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql")) properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql")) return properties } @Bean @Autowired public HibernateTransactionManager transactionManager(SessionFactory s) { HibernateTransactionManager txManager = new HibernateTransactionManager() txManager.setSessionFactory(s) return txManager } }
jdbc.driverClassName = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://localhost:3306/yiibai jdbc.username = myuser jdbc.password = passwd123 hibernate.dialect = org.hibernate.dialect.MySQLDialect hibernate.show_sql = true hibernate.format_sql = true
第8步:创建控制器
package com.yiibai.springmvc.controller import java.util.List import java.util.Locale import javax.validation.Valid import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.MessageSource import org.springframework.stereotype.Controller import org.springframework.ui.ModelMap import org.springframework.validation.BindingResult import org.springframework.validation.FieldError import org.springframework.web.bind.annotation.ModelAttribute import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestMethod import org.springframework.web.bind.annotation.SessionAttributes import com.yiibai.springmvc.model.User import com.yiibai.springmvc.model.UserProfile import com.yiibai.springmvc.service.UserProfileService import com.yiibai.springmvc.service.UserService @Controller @RequestMapping("/") @SessionAttributes("roles") public class AppController { @Autowired UserService userService @Autowired UserProfileService userProfileService @Autowired MessageSource messageSource /** * This method will list all existing users. */ @RequestMapping(value = { "/", "/list" }, method = RequestMethod.GET) public String listUsers(ModelMap model) { List<User> users = userService.findAllUsers() model.addAttribute("users", users) return "userslist" } /** * This method will provide the medium to add a new user. */ @RequestMapping(value = { "/newuser" }, method = RequestMethod.GET) public String newUser(ModelMap model) { User user = new User() model.addAttribute("user", user) model.addAttribute("edit", false) return "registration" } /** * This method will be called on form submission, handling POST request for * saving user in database. It also validates the user input */ @RequestMapping(value = { "/newuser" }, method = RequestMethod.POST) public String saveUser(@Valid User user, BindingResult result, ModelMap model) { if (result.hasErrors()) { return "registration" } /* * Preferred way to achieve uniqueness of field [sso] should be implementing custom @Unique annotation * and applying it on field [sso] of Model class [User]. * * Below mentioned peace of code [if block] is to demonstrate that you can fill custom errors outside the validation * framework as well while still using internationalized messages. * */ if(!userService.isUserSSOUnique(user.getId(), user.getSsoId())){ FieldError ssoError =new FieldError("user","ssoId",messageSource.getMessage("non.unique.ssoId", new String[]{user.getSsoId()}, Locale.getDefault())) result.addError(ssoError) return "registration" } userService.saveUser(user) model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " registered successfully") //return "success" return "registrationsuccess" } /** * This method will provide the medium to update an existing user. */ @RequestMapping(value = { "/edit-user-{ssoId}" }, method = RequestMethod.GET) public String editUser(@PathVariable String ssoId, ModelMap model) { User user = userService.findBySSO(ssoId) model.addAttribute("user", user) model.addAttribute("edit", true) return "registration" } /** * This method will be called on form submission, handling POST request for * updating user in database. It also validates the user input */ @RequestMapping(value = { "/edit-user-{ssoId}" }, method = RequestMethod.POST) public String updateUser(@Valid User user, BindingResult result, ModelMap model, @PathVariable String ssoId) { if (result.hasErrors()) { return "registration" } /*//Uncomment below &aposif block&apos if you WANT TO ALLOW UPDATING SSO_ID in UI which is a unique key to a User. if(!userService.isUserSSOUnique(user.getId(), user.getSsoId())){ FieldError ssoError =new FieldError("user","ssoId",messageSource.getMessage("non.unique.ssoId", new String[]{user.getSsoId()}, Locale.getDefault())) result.addError(ssoError) return "registration" }*/ userService.updateUser(user) model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " updated successfully") return "registrationsuccess" } /** * This method will delete an user by it&aposs SSOID value. */ @RequestMapping(value = { "/delete-user-{ssoId}" }, method = RequestMethod.GET) public String deleteUser(@PathVariable String ssoId) { userService.deleteUserBySSO(ssoId) return "redirect:/list" } /** * This method will provide UserProfile list to views */ @ModelAttribute("roles") public List<UserProfile> initializeProfiles() { return userProfileService.findAll() } }
NotEmpty.user.firstName=First name can not be blank. NotEmpty.user.lastName=Last name can not be blank. NotEmpty.user.email=Email can not be blank. NotEmpty.user.password=Password can not be blank. NotEmpty.user.ssoId=SSO ID can not be blank. NotEmpty.user.userProfiles=At least one profile must be selected. non.unique.ssoId=SSO ID {0} already exist. Please fill in different value.
第9步:创建转换器
package com.yiibai.springmvc.converter import org.springframework.beans.factory.annotation.Autowired import org.springframework.core.convert.converter.Converter import org.springframework.stereotype.Component import com.yiibai.springmvc.model.UserProfile import com.yiibai.springmvc.service.UserProfileService /** * A converter class used in views to map id&aposs to actual userProfile objects. */ @Component public class RoleToUserProfileConverter implements Converter<Object, UserProfile>{ @Autowired UserProfileService userProfileService /** * Gets UserProfile by Id * @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object) */ public UserProfile convert(Object element) { Integer id = Integer.parseInt((String)element) UserProfile profile= userProfileService.findById(id) System.out.println("Profile : "+profile) return profile } }
第10步、创建Spring配置文件
package com.yiibai.springmvc.configuration import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.MessageSource import org.springframework.context.annotation.Bean import org.springframework.context.annotation.ComponentScan import org.springframework.context.annotation.Configuration import org.springframework.context.support.ResourceBundleMessageSource import org.springframework.format.FormatterRegistry import org.springframework.web.servlet.config.annotation.EnableWebMvc import org.springframework.web.servlet.config.annotation.PathMatchConfigurer import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry import org.springframework.web.servlet.config.annotation.ViewResolverRegistry import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter import org.springframework.web.servlet.view.InternalResourceViewResolver import org.springframework.web.servlet.view.JstlView import com.yiibai.springmvc.converter.RoleToUserProfileConverter @Configuration @EnableWebMvc @ComponentScan(basePackages = "com.yiibai.springmvc") public class AppConfig extends WebMvcConfigurerAdapter{ @Autowired RoleToUserProfileConverter roleToUserProfileConverter /** * Configure ViewResolvers to deliver preferred views. */ @Override public void configureViewResolvers(ViewResolverRegistry registry) { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver() viewResolver.setViewClass(JstlView.class) viewResolver.setPrefix("/WEB-INF/views/") viewResolver.setSuffix(".jsp") registry.viewResolver(viewResolver) } /** * Configure ResourceHandlers to serve static resources like CSS/ Javascript etc... */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("/static/") } /** * Configure Converter to be used. * In our example, we need a converter to convert string values[Roles] to UserProfiles in newUser.jsp */ @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(roleToUserProfileConverter) } /** * Configure MessageSource to lookup any validation/error message in internationalized property files */ @Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource() messageSource.setBasename("messages") return messageSource } /**Optional. It&aposs only required when handling &apos.&apos in @PathVariables which otherwise ignore everything after last &apos.&apos in @PathVaidables argument. * It&aposs a known bug in Spring [https://jira.spring.io/browse/SPR-6164], still present in Spring 4.1.7. * This is a workaround for this issue. */ @Override public void configurePathMatch(PathMatchConfigurer matcher) { matcher.setUseRegisteredSuffixPatternMatch(true) } }%uA0
第一个有趣的事情是注册转换器,我们在上一步中使用addFormatters创建了Spring配置。其次是方法configurePathMatch它提供了一个解决方法(虽然其他解决方法存在)在Spring中是一个已知的错误,这仍然在Spring4.1.7.RELEASE中有发现。
<mvc:annotation-driven conversion-service="conversionService"/> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <list> <bean id="roleToUserProfile" class="com.yiibai.springsecurity.configuration.RoleToUserProfileConverter" /> </list> </property> </bean>
package com.yiibai.springmvc.configuration import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { AppConfig.class } } @Override protected Class<?>[] getServletConfigClasses() { return null } @Override protected String[] getServletMappings() { return new String[] { "/" } } }
第11步:添加视图/%uA0JSP
userslist.jsp
<%@ page language="java" contentType="text/html charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <meta http-equiv="Content-Type" content="text/html charset=ISO-8859-1"> <title>Users List</title> <link href="<c:url value=&apos/static/css/bootstrap.css&apos />" rel="stylesheet"></link> <link href="<c:url value=&apos/static/css/app.css&apos />" rel="stylesheet"></link> </head> <body> <div class="generic-container"> <div class="panel panel-default"> <!-- Default panel contents --> <div class="panel-heading"><span class="lead">List of Users </span></div> <table class="table table-hover"> <thead> <tr> <th>Firstname</th> <th>Lastname</th> <th>Email</th> <th>SSO ID</th> <th width="100"></th> <th width="100"></th> </tr> </thead> <tbody> <c:forEach items="${users}" var="user"> <tr> <td>${user.firstName}</td> <td>${user.lastName}</td> <td>${user.email}</td> <td>${user.ssoId}</td> <td><a href="<c:url value=&apos/edit-user-${user.ssoId}&apos />" class="btn btn-success custom-width">edit</a></td> <td><a href="<c:url value=&apos/delete-user-${user.ssoId}&apos />" class="btn btn-danger custom-width">delete</a></td> </tr> </c:forEach> </tbody> </table> </div> <div class="well"> <a href="<c:url value=&apos/newuser&apos />">Add New User</a> </div> </div> </body> </html>
registration.jsp
<%@ page language="java" contentType="text/html charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <meta http-equiv="Content-Type" content="text/html charset=ISO-8859-1"> <title>User Registration Form</title> <link href="<c:url value=&apos/static/css/bootstrap.css&apos />" rel="stylesheet"></link> <link href="<c:url value=&apos/static/css/app.css&apos />" rel="stylesheet"></link> </head> <body> <div class="generic-container"> <div class="well lead">User Registration Form</div> <form:form method="POST" modelAttribute="user" class="form-horizontal"> <form:input type="hidden" path="id" id="id"/> <div class="row"> <div class="form-group col-md-12"> <label class="col-md-3 control-lable" for="firstName">First Name</label> <div class="col-md-7"> <form:input type="text" path="firstName" id="firstName" class="form-control input-sm"/> <div class="has-error"> <form:errors path="firstName" class="help-inline"/> </div> </div> </div> </div> <div class="row"> <div class="form-group col-md-12"> <label class="col-md-3 control-lable" for="lastName">Last Name</label> <div class="col-md-7"> <form:input type="text" path="lastName" id="lastName" class="form-control input-sm" /> <div class="has-error"> <form:errors path="lastName" class="help-inline"/> </div> </div> </div> </div> <div class="row"> <div class="form-group col-md-12"> <label class="col-md-3 control-lable" for="ssoId">SSO ID</label> <div class="col-md-7"> <c:choose> <c:when test="${edit}"> <form:input type="text" path="ssoId" id="ssoId" class="form-control input-sm" disabled="true"/> </c:when> <c:otherwise> <form:input type="text" path="ssoId" id="ssoId" class="form-control input-sm" /> <div class="has-error"> <form:errors path="ssoId" class="help-inline"/> </div> </c:otherwise> </c:choose> </div> </div> </div> <div class="row"> <div class="form-group col-md-12"> <label class="col-md-3 control-lable" for="password">Password</label> <div class="col-md-7"> <form:input type="password" path="password" id="password" class="form-control input-sm" /> <div class="has-error"> <form:errors path="password" class="help-inline"/> </div> </div> </div> </div> <div class="row"> <div class="form-group col-md-12"> <label class="col-md-3 control-lable" for="email">Email</label> <div class="col-md-7"> <form:input type="text" path="email" id="email" class="form-control input-sm" /> <div class="has-error"> <form:errors path="email" class="help-inline"/> </div> </div> </div> </div> <div class="row"> <div class="form-group col-md-12"> <label class="col-md-3 control-lable" for="userProfiles">Roles</label> <div class="col-md-7"> <form:select path="userProfiles" items="${roles}" multiple="true" itemValue="id" itemLabel="type" class="form-control input-sm" /> <div class="has-error"> <form:errors path="userProfiles" class="help-inline"/> </div> </div> </div> </div> <div class="row"> <div class="form-actions floatRight"> <c:choose> <c:when test="${edit}"> <input type="submit" value="Update" class="btn btn-primary btn-sm"/> or <a href="<c:url value=&apos/list&apos />">Cancel</a> </c:when> <c:otherwise> <input type="submit" value="Register" class="btn btn-primary btn-sm"/> or <a href="<c:url value=&apos/list&apos />">Cancel</a> </c:otherwise> </c:choose> </div> </div> </form:form> </div> </body> </html>
registrationsuccess.jsp
<%@ page language="java" contentType="text/html charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <meta http-equiv="Content-Type" content="text/html charset=ISO-8859-1"> <title>Registration Confirmation Page</title> <link href="<c:url value=&apos/static/css/bootstrap.css&apos />" rel="stylesheet"></link> <link href="<c:url value=&apos/static/css/app.css&apos />" rel="stylesheet"></link> </head> <body> <div class="generic-container"> <div class="alert alert-success lead"> ${success} </div> <span class="well floatRight"> Go to <a href="<c:url value=&apos/list&apos />">Users List</a> </span> </div> </body> </html>
app.css
body, #mainWrapper { height: 100% background-color:rgb(245, 245, 245) } body, .form-control{ font-size:14px!important } .floatRight{ float:right margin-right: 18px } .has-error{ color:red } .generic-container { position:fixed width:80% margin-left: 20px margin-top: 20px margin-bottom: 20px padding: 20px background-color: #EAE7E7 border: 1px solid #ddd border-radius: 4px box-shadow: 0 0 30px black } .custom-width { width: 80px !important }
第12步:构建,部署和运行应用程序
现在构建War(前面提到的Eclipse教程)或通过Maven的命令行( mvn clean install).%uA0部署%uA0war%uA0到Servlet3.0容器。
打开浏览器,浏览URL =>%uA0http://localhost:8080/SpringMVCMany2ManyCRUD/
点击 ‘Add New User’
Submit.
点击 ‘Users List’ 链接:
添加更多的用户信息:
提交,如下结果显示:
现在回到列表,点击删除“Si”用户。
到这里,整个教程介绍完毕,包教不包会!