【本系列其他教程正在陆续翻译中,点击分类:spring 4 mvc 进行查看。源码下载地址在文章末尾。】
【翻译 by 明明如月 QQ 605283073】
下载地址:http://websystique.com/springmvc/spring-mvc-4-fileupload-download-hibernate-example/
上一篇:
本文要点:
由于本文比较常,你可以直接跳到你感兴趣的部分开始阅读。
----------------------------------------
所需技术和软件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.websystique.springmvc</groupId> <artifactId>Spring4MVCFileUploadDownloadWithHibernate</artifactId> <packaging>war</packaging> <version>1.0.0</version> <name>Spring4MVCFileUploadDownloadWithHibernate Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <springframework.version>4.2.0.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-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.4</version> <configuration> <warSourceDirectory>src/main/webapp</warSourceDirectory> <warName>Spring4MVCFileUploadDownloadWithHibernate</warName> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </pluginManagement> <finalName>Spring4MVCFileUploadDownloadWithHibernate</finalName> </build> </project>
create table APP_USER ( id BIGINT NOT NULL AUTO_INCREMENT, sso_id VARCHAR(30) 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_DOCUMENT( id BIGINT NOT NULL AUTO_INCREMENT, user_id BIGINT NOT NULL, name VARCHAR(100) NOT NULL, description VARCHAR(255) , type VARCHAR(100) NOT NULL, content longblob NOT NULL, PRIMARY KEY (id), CONSTRAINT document_user FOREIGN KEY (user_id) REFERENCES APP_USER (id) ON UPDATE CASCADE ON DELETE CASCADE );
注意:content longblob 。我们将把文件以二进制的形式存入该列。
package com.websystique.springmvc.model; import javax.persistence.Basic; 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.Lob; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name="USER_DOCUMENT") public class UserDocument { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id; @Column(name="name", length=100, nullable=false) private String name; @Column(name="description", length=255) private String description; @Column(name="type", length=100, nullable=false) private String type; @Lob @Basic(fetch = FetchType.LAZY) @Column(name="content", nullable=false) private byte[] content; @ManyToOne(optional = false) @JoinColumn(name = "USER_ID") private User user; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getType() { return type; } public void setType(String type) { this.type = type; } public byte[] getContent() { return content; } public void setContent(byte[] content) { this.content = content; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof UserDocument)) return false; UserDocument other = (UserDocument) obj; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public String toString() { return "UserDocument [id=" + id + ", name=" + name + ", description=" + description + ", type=" + type + "]"; } }
@Lob @Basic(fetch = FetchType.LAZY) @Column(name="content", nullable=false) private byte[] content;
@Lob指明
longblob持久化属性将以大对象的形式存入数据库
.
@Basic注解是一个可选注解
, 在这里是告诉hibernate对此二进制内容执行懒加载。
package com.websystique.springmvc.model; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; 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="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; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) private Set<UserDocument> userDocuments = new HashSet<UserDocument>(); 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 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<UserDocument> getUserDocuments() { return userDocuments; } public void setUserDocuments(Set<UserDocument> userDocuments) { this.userDocuments = userDocuments; } @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 + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + "]"; } }
package com.websystique.springmvc.dao; import java.util.List; import com.websystique.springmvc.model.UserDocument; public interface UserDocumentDao { List<UserDocument> findAll(); UserDocument findById(int id); void save(UserDocument document); List<UserDocument> findAllByUserId(int userId); void deleteById(int id); }
package com.websystique.springmvc.dao; import java.util.List; import org.hibernate.Criteria; import org.hibernate.criterion.Restrictions; import org.springframework.stereotype.Repository; import com.websystique.springmvc.model.UserDocument; @Repository("userDocumentDao") public class UserDocumentDaoImpl extends AbstractDao<Integer, UserDocument> implements UserDocumentDao{ @SuppressWarnings("unchecked") public List<UserDocument> findAll() { Criteria crit = createEntityCriteria(); return (List<UserDocument>)crit.list(); } public void save(UserDocument document) { persist(document); } public UserDocument findById(int id) { return getByKey(id); } @SuppressWarnings("unchecked") public List<UserDocument> findAllByUserId(int userId){ Criteria crit = createEntityCriteria(); Criteria userCriteria = crit.createCriteria("user"); userCriteria.add(Restrictions.eq("id", userId)); return (List<UserDocument>)crit.list(); } public void deleteById(int id) { UserDocument document = getByKey(id); delete(document); } }
package com.websystique.springmvc.dao; import java.util.List; import com.websystique.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.websystique.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.websystique.springmvc.model.User; @Repository("userDao") public class UserDaoImpl extends AbstractDao<Integer, User> implements UserDao { public User findById(int id) { User user = getByKey(id); 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(); 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(); 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.websystique.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.websystique.springmvc.service; import java.util.List; import com.websystique.springmvc.model.UserDocument; public interface UserDocumentService { UserDocument findById(int id); List<UserDocument> findAll(); List<UserDocument> findAllByUserId(int id); void saveDocument(UserDocument document); void deleteById(int id); }
package com.websystique.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.websystique.springmvc.dao.UserDocumentDao; import com.websystique.springmvc.model.UserDocument; @Service("userDocumentService") @Transactional public class UserDocumentServiceImpl implements UserDocumentService{ @Autowired UserDocumentDao dao; public UserDocument findById(int id) { return dao.findById(id); } public List<UserDocument> findAll() { return dao.findAll(); } public List<UserDocument> findAllByUserId(int userId) { return dao.findAllByUserId(userId); } public void saveDocument(UserDocument document){ dao.save(document); } public void deleteById(int id){ dao.deleteById(id); } }
package com.websystique.springmvc.service; import java.util.List; import com.websystique.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.websystique.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.websystique.springmvc.dao.UserDao; import com.websystique.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.setFirstName(user.getFirstName()); entity.setLastName(user.getLastName()); entity.setEmail(user.getEmail()); entity.setUserDocuments(user.getUserDocuments()); } } 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))); } }
package com.websystique.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.websystique.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.websystique.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/websystique jdbc.username = myuser jdbc.password = mypassword hibernate.dialect = org.hibernate.dialect.MySQLDialect hibernate.show_sql = true hibernate.format_sql = true
Spring提供了文件上穿的很多选择. 我们使用其中一种方式, SpringMVC DispatcherServlet的 javax.servlet.MultipartConfigElement
. 这提供了很多可设置的属性如文件最大大小,请求大小,位置和上传过程中文件暂时存在磁盘的入口。
另外, 我们还需要在Spring配置中添加StandardServletMultipartResolver
Bean . 它是基于Servlet 3.0javax.servlet.http.Part
API 的MultipartResolver
接口的标准实现类。
package com.websystique.springmvc.configuration; import javax.servlet.MultipartConfigElement; import javax.servlet.ServletRegistration; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class HelloWorldInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { HelloWorldConfiguration.class }; } @Override protected Class<?>[] getServletConfigClasses() { return null; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected void customizeRegistration(ServletRegistration.Dynamic registration) { registration.setMultipartConfig(getMultipartConfigElement()); } private MultipartConfigElement getMultipartConfigElement(){ MultipartConfigElement multipartConfigElement = new MultipartConfigElement(LOCATION, MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD); return multipartConfigElement; } /*Set these variables for your project needs*/ private static final String LOCATION = "C:/mytemp/"; private static final long MAX_FILE_SIZE = 1024 * 1024 * 25;//25MB private static final long MAX_REQUEST_SIZE = 1024 * 1024 * 30;//30MB private static final int FILE_SIZE_THRESHOLD = 0; }
package com.websystique.springmvc.configuration; 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.web.multipart.support.StandardServletMultipartResolver; 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; @Configuration @EnableWebMvc @ComponentScan(basePackages = "com.websystique.springmvc") public class HelloWorldConfiguration extends WebMvcConfigurerAdapter{ @Bean(name="multipartResolver") public StandardServletMultipartResolver resolver(){ return new StandardServletMultipartResolver(); } /** * 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 MessageSource to lookup any validation/error message in internationalized property files */ @Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("messages"); return messageSource; } }
Spring 提供 org.springframework.web.multipart.MultipartFile
代表请求传来的上传文件。它提供了像getName(), getContentType(), getBytes(), getInputStream() 这些方法,使得处理上传的文件非常容易。
我们写文件的包装类
package com.websystique.springmvc.model; import org.springframework.web.multipart.MultipartFile; public class FileBucket { MultipartFile file; String description; public MultipartFile getFile() { return file; } public void setFile(MultipartFile file) { this.file = file; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
package com.websystique.springmvc.controller; import java.io.IOException; import java.util.List; import java.util.Locale; import javax.servlet.http.HttpServletResponse; 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.util.FileCopyUtils; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; 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.multipart.MultipartFile; import com.websystique.springmvc.model.FileBucket; import com.websystique.springmvc.model.User; import com.websystique.springmvc.model.UserDocument; import com.websystique.springmvc.service.UserDocumentService; import com.websystique.springmvc.service.UserService; import com.websystique.springmvc.util.FileValidator; @Controller @RequestMapping("/") public class AppController { @Autowired UserService userService; @Autowired UserDocumentService userDocumentService; @Autowired MessageSource messageSource; @Autowired FileValidator fileValidator; @InitBinder("fileBucket") protected void initBinder(WebDataBinder binder) { binder.setValidator(fileValidator); } /** * 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("user", 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"; } userService.updateUser(user); model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " updated successfully"); return "registrationsuccess"; } /** * This method will delete an user by it's SSOID value. */ @RequestMapping(value = { "/delete-user-{ssoId}" }, method = RequestMethod.GET) public String deleteUser(@PathVariable String ssoId) { userService.deleteUserBySSO(ssoId); return "redirect:/list"; } @RequestMapping(value = { "/add-document-{userId}" }, method = RequestMethod.GET) public String addDocuments(@PathVariable int userId, ModelMap model) { User user = userService.findById(userId); model.addAttribute("user", user); FileBucket fileModel = new FileBucket(); model.addAttribute("fileBucket", fileModel); List<UserDocument> documents = userDocumentService.findAllByUserId(userId); model.addAttribute("documents", documents); return "managedocuments"; } @RequestMapping(value = { "/download-document-{userId}-{docId}" }, method = RequestMethod.GET) public String downloadDocument(@PathVariable int userId, @PathVariable int docId, HttpServletResponse response) throws IOException { UserDocument document = userDocumentService.findById(docId); response.setContentType(document.getType()); response.setContentLength(document.getContent().length); response.setHeader("Content-Disposition","attachment; filename=\"" + document.getName() +"\""); FileCopyUtils.copy(document.getContent(), response.getOutputStream()); return "redirect:/add-document-"+userId; } @RequestMapping(value = { "/delete-document-{userId}-{docId}" }, method = RequestMethod.GET) public String deleteDocument(@PathVariable int userId, @PathVariable int docId) { userDocumentService.deleteById(docId); return "redirect:/add-document-"+userId; } @RequestMapping(value = { "/add-document-{userId}" }, method = RequestMethod.POST) public String uploadDocument(@Valid FileBucket fileBucket, BindingResult result, ModelMap model, @PathVariable int userId) throws IOException{ if (result.hasErrors()) { System.out.println("validation errors"); User user = userService.findById(userId); model.addAttribute("user", user); List<UserDocument> documents = userDocumentService.findAllByUserId(userId); model.addAttribute("documents", documents); return "managedocuments"; } else { System.out.println("Fetching file"); User user = userService.findById(userId); model.addAttribute("user", user); saveDocument(fileBucket, user); return "redirect:/add-document-"+userId; } } private void saveDocument(FileBucket fileBucket, User user) throws IOException{ UserDocument document = new UserDocument(); MultipartFile multipartFile = fileBucket.getFile(); document.setName(multipartFile.getOriginalFilename()); document.setDescription(fileBucket.getDescription()); document.setType(multipartFile.getContentType()); document.setContent(multipartFile.getBytes()); document.setUser(user); userDocumentService.saveDocument(document); } }
package com.websystique.springmvc.util; import org.springframework.stereotype.Component; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import com.websystique.springmvc.model.FileBucket; @Component public class FileValidator implements Validator { public boolean supports(Class<?> clazz) { return FileBucket.class.isAssignableFrom(clazz); } public void validate(Object obj, Errors errors) { FileBucket file = (FileBucket) obj; if(file.getFile()!=null){ if (file.getFile().getSize() == 0) { errors.rejectValue("file", "missing.file"); } } } }
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.ssoId=SSO ID can not be blank. non.unique.ssoId=SSO ID {0} already exist. Please fill in different value. missing.file= Please select a file.
<%@ 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" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Upload/Download/Delete Documents</title> <link href="<c:url value='/static/css/bootstrap.css' />" rel="stylesheet"></link> <link href="<c:url value='/static/css/app.css' />" 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 Documents </span></div> <div class="tablecontainer"> <table class="table table-hover"> <thead> <tr> <th>No.</th> <th>File Name</th> <th>Type</th> <th>Description</th> <th width="100"></th> <th width="100"></th> </tr> </thead> <tbody> <c:forEach items="${documents}" var="doc" varStatus="counter"> <tr> <td>${counter.index + 1}</td> <td>${doc.name}</td> <td>${doc.type}</td> <td>${doc.description}</td> <td><a href="<c:url value='/download-document-${user.id}-${doc.id}' />" class="btn btn-success custom-width">download</a></td> <td><a href="<c:url value='/delete-document-${user.id}-${doc.id}' />" class="btn btn-danger custom-width">delete</a></td> </tr> </c:forEach> </tbody> </table> </div> </div> <div class="panel panel-default"> <div class="panel-heading"><span class="lead">Upload New Document</span></div> <div class="uploadcontainer"> <form:form method="POST" modelAttribute="fileBucket" enctype="multipart/form-data" class="form-horizontal"> <div class="row"> <div class="form-group col-md-12"> <label class="col-md-3 control-lable" for="file">Upload a document</label> <div class="col-md-7"> <form:input type="file" path="file" id="file" class="form-control input-sm"/> <div class="has-error"> <form:errors path="file" 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="description">Description</label> <div class="col-md-7"> <form:input type="text" path="description" id="description" class="form-control input-sm"/> </div> </div> </div> <div class="row"> <div class="form-actions floatRight"> <input type="submit" value="Upload" class="btn btn-primary btn-sm"> </div> </div> </form:form> </div> </div> <div class="well"> Go to <a href="<c:url value='/list' />">Users List</a> </div> </div> </body> </html>
主要部分是 关于文件的enctype="multipart/form-data"
和 input type="file"
.
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='/static/css/bootstrap.css' />" rel="stylesheet"></link> <link href="<c:url value='/static/css/app.css' />" 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="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-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='/list' />">Cancel</a> </c:when> <c:otherwise> <input type="submit" value="Register" class="btn btn-primary btn-sm"/> or <a href="<c:url value='/list' />">Cancel</a> </c:otherwise> </c:choose> </div> </div> <c:if test="${edit}"> <span class="well pull-left"> <a href="<c:url value='/add-document-${user.id}' />">Click here to upload/manage your documents</a> </span> </c:if> </form:form> </div> </body> </html>
<%@ 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='/static/css/bootstrap.css' />" rel="stylesheet"></link> <link href="<c:url value='/static/css/app.css' />" rel="stylesheet"></link> </head> <body> <div class="generic-container"> <div class="alert alert-success lead"> ${success} </div> <span class="well pull-left"> <a href="<c:url value='/add-document-${user.id}' />">Click here to upload/manage your documents</a> </span> <span class="well pull-right"> Go to <a href="<c:url value='/list' />">Users List</a> </span> </div> </body> </html>
<%@ 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='/static/css/bootstrap.css' />" rel="stylesheet"></link> <link href="<c:url value='/static/css/app.css' />" 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> <div class="tablecontainer"> <table class="table table-hover"> <thead> <tr> <th>First Name</th> <th>Last Name</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='/edit-user-${user.ssoId}' />" class="btn btn-success custom-width">edit</a></td> <td><a href="<c:url value='/delete-user-${user.ssoId}' />" class="btn btn-danger custom-width">delete</a></td> </tr> </c:forEach> </tbody> </table> </div> </div> <div class="well"> <a href="<c:url value='/newuser' />">Add New User</a> </div> </div> </body> </html>
在文件上传过程中,可能会出现“Packet for query is too large”.
为了避免这个问题,需要设置Mysql 配置文件中的‘max_allowed_packet’值.
默认是 4M. 你可以根据自己情况配置。
max_allowed_packet=256M
修改配置后不要忘了重启MySQL Server
你可以通过以下语句进行查询
>show variables like ‘max%’ ;
还可以上传更多文件:
验证数据库:验证数据库:
不选择文件直接点上传将会显示 请选择文件的提示
项目下载地址:http://websystique.com/?smd_process_download=1&download_id=1789