【本系列其他教程正在陆续翻译中,点击分类:spring 4 mvc 进行查看。源码下载地址在文章末尾。】
【翻译 by 明明如月 QQ 605283073】
下载地址:http://websystique.com/springmvc/spring-mvc-4-fileupload-download-hibernate-example/
上一篇:
Spring MVC 4 RESTFul Web Services CRUD例子(带源码)【这才是restful,超经典】
下一篇:Spring MVC 4 使用常规的fileupload上传文件(带源码)
本文介绍使用Spring MVC 4, Hibernate & MySQL 数据库实现文件上传. Spring MVC 结合Hibernate+MySQL文件上传到数据库的例子, 以及下载和删除.
本文要点:
- 准备数据库 [创建所需的表]
- 准备Model类, DAO and Service 层[将被控制器用来处理文件upload/download/delete操作]
- 准备Hibernate 配置
- 准备 Spring 对文件上传下载删除的配置
- 运行应用实现文件上传、下载、删除
由于本文比较常,你可以直接跳到你感兴趣的部分开始阅读。
—————————————-
所需技术和软件
- Spring 4.2.0.RELEASE
- Hibernate 4.3.10.Final
- MySQL Server 5.6
- validation-api 1.1.0.Final
- hibernate-validator 5.1.3.Final
- Bootstrap v3.3.2
- Maven 3
- JDK 1.7
- Tomcat 8.0.21
- Eclipse JUNO Service Release 2
让我们开始吧。。。
项目目录结构
第2步: 在 pom.xml 文件中声明依赖
<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>
创建数据库模式
我们将展示用户和问题的关系,一个用户可以又多个文档,用户和文档的关系是一对多(
OneToMany )的关系。
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;
我们选择byte[]来存储文件内容.
@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 + "]";
}
}
创建DAO层
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.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);
}
}
创建Service层
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)));
}
}
创建Hibernate配置类
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;
}
}
使用下面配置文件
application.properties
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;
}
注意: 我们重写了customizeRegistration方法将需要的MultiPartConfigElement注入到DispatcherServlet中.下一步是通过注册StandardServletMultipartResolver Bean 激活多文件支持。
Spring配置类
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;
}
}
创建File包装类
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;
}
}
创建Spring MVC控制器类
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);
}
}
创建Validator
创建简单的
validator实现对文件的校验
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");
}
}
}
}
messages.properties
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.
创建视图
managedocuments.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" %>
<%@ 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>
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='/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>
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='/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’值.
- 在Windows系统中MySQL Server 5.6/my.ini
- 在Linux在etc/my.cnf
默认是 4M. 你可以根据自己情况配置。
max_allowed_packet=256M
修改配置后不要忘了重启MySQL Server
你可以通过以下语句进行查询
>show variables like ‘max%’ ;
构建, 部署和运行
在tomcat发布后 浏览器输入
http://localhost:8080/Spring4MVCFileUploadDownloadWithHibernate
创建用户
填充并提交后
还可以上传更多文件:
验证数据库:
点击下载 文件也可以被下载下来:
点击 删除,文件将被删除
验证数据库:
不选择文件直接点上传将会显示 请选择文件的提示
项目下载地址:http://websystique.com/?smd_process_download=1&download_id=1789
特别说明:此系列教程有的童鞋下载下来运行 经常404 或者改成xml方式以后
缺少org.springframework.web.context.ContextLoaderServlet等
参见:http://blog.csdn.net/w605283073/article/details/52126347
原文链接:https://blog.csdn.net/w605283073/article/details/51339925
本站声明:网站内容来源于网络,如有侵权,请联系我们,我们将及时处理。
评论前必须登录!
立即登录