SpringMVC从入门到掌握
文章目录
- SpringMVC从入门到掌握
- 1. SpringMvc的概述
- 2. SpringMvc的搭建
- 3. SpringMvc的常用注解总结
- 4. 实体对象绑定请求参数
- 5. 处理数据模型
- 6. 关于重定向与转发
- 7. REST的描述
- 8. REST的限制与优点
- 9. HTTP请求的四种状态
- 10. 数据转换器
- 创建测试方法
- 11. 数据校验
- hibernate Validator扩展注解
- 12. 基于Accept-Language实现国际化
- 13. 基于HttpSession实现国际化(多种手动语言切换)
- 14. 拦截器
- 15. 文件的上传与下载
- 16. 异常的处理方式
1. SpringMvc的概述
- Spring MVC为展现层提供的基于MVC设计理念的优秀Web框架,是目前最主流的MVC框架之一。
- Spring3.0后全面超越了Struts2,称为最优秀的MVC框架。
- Spring MVC通过一套MVC注解,让POJO称为处理请求的控制器,无需实现任何接口。
- 支持REST风格的Web请求。采用了松散耦合可插拔组件结构,比其它MVC框架更具扩展性和灵活性。
2. SpringMvc的搭建
- 导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.1.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.13.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jboss.logging/jboss-logging -->
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.3.2.Final</version>
</dependency>
- 配置xml文件
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!-- SpringMVC配置文件路径 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 启动时自动加载配置文件 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 注意:如果没有配置 init-param 设置文件路径,SpringMvc默认回去WEB-INF下查询 servlet-nameservlet.xml -->
- 创建处理类
注解
@Controller // 修饰类为一个控制器
public class HelloWorld {
@RequestMapping("/hello") // 修饰方法(或类)的请求路径
public String hello(){
System.out.println("hello spring mvc");
return "hello"; // 视图
}
}
<!-- 配置Spring MVC自动扫描的路径 -->
<context:component-scan base-package="com.*.controller" />
<!-- 配置视图解析器 将视图返回字符串解析到:/WEB-INF/view/返回值.jsp 下-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/view/" />
<!-- 视图后置 -->
<property name="suffix" value=".jsp" />
</bean>
接口
public class HelloWorld implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("HelloWorld");
return new ModelAndView("hello"); // 视图
}
}
<!-- name:代表访问路径 class:指定控制器类 -->
<bean name="/helloworld" class="com.znsd.controller.HelloWorld" />
两种方式,推荐使用注解 (不是必须,分情况而待)
3. SpringMvc的常用注解总结
- @Component:一个普通的Bean类。
- @Repository :用于标注持久层DAO类
- @Service :用于标注业务层类
- @Controller :用于标注控制器类
- @RequestMapping:
- 类定义处:提供初步的映射信息,为该类下所有请求方法添加前缀。
- 方法定义处:提供进一步的映射信息,提供方法的请求路径。
@Controller
@RequestMapping("world") // 类似Struts2的@Namespace(命名空间)
public class HelloWorld {
@RequestMapping("/hello")
public String hello(){
System.out.println("hello spring mvc");
return "hello";
}
}
- @RequestMapping 的 value、method、params及heads分别表示请求url,请求方法,请求参数及请求头的映射条件,他们之间是与的关系,联合使用多个条件可以让请求更加精确化。
- 在@RequestMapping 中 还支持 Ant风格的URL。
- ?:匹配文件中一个字符。
- *:匹配文件中任意字符。
- **:匹配多层路径。
/user/*/create:匹配/user/aaa/create,/user/bbb/crate
/user/**/create:匹配/user/create,/user/aaa/bbb/create
/user/create??:匹配/user/createaa,/user/createbb
- @PathVariable:URL模版方式
// @PathVariable:用来映射URL中的占位符。映射的变量名必须和占位符中的名称一致。
@RequestMapping("/delete/{userid}")
public String delete(@PathVariable("userid")int userid) {
System.out.println("userid=" + userid);
return "hello";
}
- @RequestParam:获取请求参数
// @RequtParam:获取页面传递过来的参数,GET和POST都支持。
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam("username")String username, @RequestParam("age")int age){
System.out.println("username=" + username);
System.out.println("age=" + age);
return "hello";
}
@RequestParam 还有三个属性
- value:指定参数的名称
- required:指定参数是否为必填 (boolean)
- defaultValue:指定参数的默认值
- @RequestHeader:获取请求头内容
// 请求头包含了若干的属性,用来获取客户端的信息。通过@RequestHeader可以用来获取请求头中的信息
@RequestMapping("/testRequestHeader")
public String testRequestHeader(@RequestHeader("Accept-Language") String language){
System.out.println("language=" + language);
return "hello";
}
- @CookiValue:获取客户端Cookie
// @CookieValue:用来获取客户端Cookie信息。
@RequestMapping("/testCookieValue")
public String testCookieValue(@CookieValue("JSESSIONID")String sessionid){
System.out.println("sessionid=" + sessionid);
return "hello";
}
- @ResponseBody:标识为Json返回
- 需要导入依赖
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.7</version>
</dependency>
@ResponseBody
@RequestMapping(value="/testJackson",method=RequestMethod.GET)
public Student testJackson() {
User user = new User();
user.setName("李相如");
return user;
}
4. 实体对象绑定请求参数
<!-- name必须和对象属性名一至 -->
<form action="world/user/create" method="post">
姓名:<input type="text" name="name"><br>
密码:<input type="text" name="pass"><br>
年龄:<input type="text" name="age"><br>
<input type="submit" value="提交" />
</form>
public class User {
private String name;
private String pass;
private int age;
}
// Spring MVC会直接将页面元素和实体对象进行匹配,自动转换为实体对象.并且支持级联属性。如address.city等。
@RequestMapping(value = "/user/create", method = RequestMethod.POST)
public String createUser(User user) {
System.out.println(user.toString());
return "hello";
}
5. 处理数据模型
Spring MVC提供一下几种途径返回模型数据:
- ModeAndView:将处理方法的返回类型设置为ModeAndView,方法体即可通过该模型对象添加模型数据。
- 控制器处理方法如果返回ModelAndView,即包含视图信息,也包含模型信息。
- 构造方法:提供了多种构造方法的重载
- 添加模型数据:
- ModelAndView addObject(String attributeName, Object attributeValue);
- ModelAndView addAllObjects(Map modelMap) ;
- 添加视图
- void setView(View view);
- void setViewName(String viewName);
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
ModelAndView modelAndView = new ModelAndView("hello");
//添加单个值
modelAndView.addObject("h","Hello Spring MVC");
return modelAndView;
}
- Map及Model形参:当形参为Map,Model,ModelMap时,处理方法返回时,Map中的数据会自动添加到模型中。
- Spring MVC在内部使用了一个Model接口存储模型数据。
- Spring MVC在调用方法前会创建一个隐含的模型对象作为数据模型的存储容器。如果传入的参数为Map或者Model类型,SpringMVC会自动将对象保存到模型数据中。
@RequestMapping("/testMap")
public String testMap(Map<String,Object> map){
map.put("mapdata", "map data");
return "hello";
}
- @SessionAttributes:将模型中的某个属性存储到Session中,以便多个请求之间共享这个属性。
- 如果希望在多个请求之间共享某个模型的数据,则可以在控制器类上标注一个@SessionAttributes,SpringMVC会将对应的属性存储到Session中。
- @SessionAttributes除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些类型放到Session中。
- @SessionAttributes(types=User.class) :将隐含模型中所有类型为User属性添加到Session中。
- @SessionAttributes(value={“user1”,“user2”}):将user1对象和user2放入Session中。
// 保存到Session中
@SessionAttributes("user")
@Controller
@RequestMapping("world")
public class HelloWorld {
@RequestMapping("/testSession")
public String testSession(Map<String,Object> map){
User user = new User();
user.setUsername("zhangsan");
user.setUserpass("123");
user.setAge(20);
map.put("user", user);
return "hello";
}
}
- @SessionAttributes只能用来修饰类。
- @ModelAttribute:方法形参标记该注解后,形参对象就会放到模型中。
- 在方法定义上定义@ModelAttribute注解:
- SpringMVC调用方法前,会优先调用方法上标注了@ModelAttributes的方法。
- 将@ModelAttributes中的属性保存到map中,可以在执行表单提交生成对象之前,替换执行方法同名的形参。
@ModelAttribute
public void before(Map<String, Object> map,User user) {
user.setName("123");
user.setPass("123456);
map.put("userInfo", user);
}
@RequestMapping(value="/testModelAttribute")
public String testModelAttribute(User user) {
student.setName("456");
System.out.println(user);
return "success";
}
### 自定义视图
// 添加一个自定义视图,实现View接口。
@Component //把视图放到IOC容器里面 ,这里视图的名字就是helloView
public class HelloView implements View {
@Override
public String getContentType() {
return "text/html";
}
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
throws Exception {
response.getWriter().println("hello view current time : " + new Date());
}
}
<!-- 通过BeanNameViewResolver定义名称视图解析器。 -->
<!-- BeanNameViewResolver 解析器:使用视图的名字来解析视图 -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<!-- order值越小优先级越高 -->
<!-- InternalResourceViewResolver的order值是inter的最大值,所以一般来说都是最后调用的 -->
<property name="order" value="100" />
</bean>
<!-- 在Spring 配置文件中将自定义视图的包添加到自动扫描路径中。 -->
<context:component-scan base-package="com.znsd.springmvc.view" />
@RequestMapping(value="/testCustomView",method=RequestMethod.GET)
public ModelAndView testCustomView() {
return new ModelAndView(new HelloView());
}
6. 关于重定向与转发
- 一般情况下,控制器返回字符串类型的值会被当成逻辑视图名进行处理。
- 如果返回字符串中带有forward:或者redirect:前缀时,SpringMVC会将其进行特殊处理。将forward:和redirect:作为指示符,其后面字符串作为url来处理。
// 当使用转发与重定向时 springmvc不会使用视图解析配置前后缀不会添加,转发可以访问WEB-INF下文件,重定向不能
@RequestMapping("forward")
public String testForward() {
return "forward:/success.jsp"; // 会完成一个到 success.jsp的转发操作。
}
@RequestMapping("redirect")
public String testRedirect() {
return "redirect:/success.jsp"; // 会完成一个到 success.jsp的重定向操作。
}
7. REST的描述
- 用URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作
- REST描述的是在网络中client和server的一种交互形式;REST本身不实用,实用的是如何设计 RESTful API(REST风格的网络接口)
- Server提供的RESTful API中,URL中只使用名词来指定资源,原则上不使用动词。“资源”是REST架构或者说整个网络处理的核心。例如:web_service/studentInfo----获取学生信息
- 用HTTP协议里的动词来实现资源的添加,修改,删除等操作。即通过HTTP动词来实现资源的状态扭转
- GET 获取资源/POST 新建资源/PUT 更新资源/DELETE 删除资源
- Server和Client之间传递某资源的一个表现形式,比如用JSON,XML传输文本,或者用JPG,WebP传输图片等。当然还可以压缩HTTP传输时的数据
- 用 HTTP Status Code传递Server的状态信息。比如最常用的 200 表示成功,500 表示Server内部错误等
8. REST的限制与优点
- 客户-服务器(Client-Server)客户端服务器分离 ,
- 提高用户界面的便携性(操作简单)
- 通过简化服务器提高可伸缩性(高性能,低成本)
- 允许组件分别优化(可以让服务端和客户端分别进行改进和优化)
- 无状态(Stateless):客户端的每个请求要包含服务器所需要的所有信息
- 提高可见性(可以单独考虑每个请求)
- 提高了可靠性(更容易从局部故障中修复)
- 提高可扩展性(降低了服务器资源使用)
- 缓存(Cachable)
- 减少交互次数,交互的平均延迟
- 分层系统(Layered System)
- 系统组件不需要知道与他交流组件之外的事情。封装服务,引入中间层,限制了系统的复杂性,提高可扩展性
- 统一接口(Uniform Interface)
- 提高交互的可见性,鼓励单独改善组件
- 支持按需代码(Code-On-Demand 可选)
- 提高可扩展性
9. HTTP请求的四种状态
- GET:获取资源
- POST:新建资源
- PUT:更新资源
- DELETE:删除资源
10. 数据转换器
- 自定义数据转换器
@Component
public class MyConverter implements Converter<String, User> {
@Override
public Student convert(String source) {//前台传过来一串字符串,通过split分割成一个String数组
String [] str = source.split("-");
User user = new User();
user.setName(str[0]);
user.setPass(str[1]);
return user;
}
}
- 将自定义的数据转换器放入SpringMvc提供的转换器中
<!-- FormattingConversionServiceFactoryBean 包含了 ConversionServiceFactoryBean ,既可以数据转换也可以数据格式化 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="myConverter" />
</set>
</property>
</bean>
- 将转换器注册到annotation-driven中
<!-- 该配置为springmvc基础配置,很多功能需要该注解来协调,建议配置文件配完后加入该注解 -->
<mvc:annotation-driven conversion-service="conversionService" />
- 创建jsp
<a href="handler/testConverter.action?studentInfo=3-第十三-?">testConverter</a>
创建测试方法
@RequestMapping(value="/testConverter",method=RequestMethod.GET)
public ModelAndView testConverter(@RequestParam("studentInfo") Student student) {
System.out.println(student);
return new ModelAndView("success");
}
11. 数据校验
注意:springMvc是没有校验的,它使用的校验是Hibernate框架的
- 导入依赖
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.13.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jboss.logging/jboss-logging -->
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.3.2.Final</version>
</dependency>
</dependencies>
- 在相应字段添加校验注解
@Email
private String email;
注解 | 说明 |
@Null | 必须为null |
@NotNull | 必须不为null |
@AssertTrue | 必须为true |
@AssertFalse | 必须为false |
@Min(value) | 必须为一个数字,其值必须大于等于指定的最小值 |
@Max(value) | 必须为一个数字,其值必须小于等于指定的最小值 |
@DecimalMin(value) | 必须为一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) | 必须为一个数字,其值必须小于等于指定的最小值 |
@Size(max,min) | 元素的大小必须在指定范围内 |
@Digits(int,fraction) | 必须是一个数字,其值必须在可接受范围内 |
@Past | 必须是一个过去的日期 |
@Future | 必须是一个将来的日期 |
@Pattern(value) | 其值必须符合指定的正则表达式 |
hibernate Validator扩展注解
- Hibernate Validator是JSR3.0的一个扩展组件,除支持所有标准的效验注解外,它还支持以下扩展注解
注解 | 说明 |
@Email | 被修饰的元素必须是电子邮件 |
@Length | 被修饰的元素长度必须在指定的范围内 |
@NotEmpty | 被修饰的元素必须非空 |
@Range | 被修饰的元素必须在合适的范围内 |
- 编写测试方法
@RequestMapping(value="/testFormat",method=RequestMethod.POST)
public String testFormat(@Valid User user, BindingResult result,Map<String, Object> map) {
if (result.getErrorCount() > 0) {
for (FieldError error : result.getFieldErrors()) {
System.out.println("------>"+error.getDefaultMessage());
map.put("errors", result.getFieldErrors());
}
}
return "login";
}
12. 基于Accept-Language实现国际化
- 编写properties
i18n_zh_CN.properties
resource.name=\u5148\u751F
resource.msg=\u4F60\u597D
i18n_en_US.properties
resource.name=先生
resource.msg=你好
- 配置bean
<!-- 国际化 springmvc会自动扫描id为messageSource的bean 然后把该bean的配置介入 -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n" />
</bean>
- 创建视图并且导入<%@ taglib uri=“http://java.sun.com/jsp/jstl/fmt” prefix=“fmt”%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<fmt:message key="resource.describe" />
<fmt:message key="resource.oneself" />
</body>
</html>
是跟据当前地区转换页面可以设置浏览器语言查看出效果
13. 基于HttpSession实现国际化(多种手动语言切换)
- 编写properties
i18n_zh_CN.properties
resource.name=\u5148\u751F
resource.msg=\u4F60\u597D
i18n_en_US.properties
resource.name=先生
resource.msg=你好
- 配置bean
<!-- 国际化 springmvc会自动扫描id为messageSource的bean 然后把该bean的配置介入 -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n" />
</bean>
<!-- 自定义国际化 -->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" >
<property name="defaultLocale" value="zh_CN" /> <!-- 默认为中文 -->
</bean>
<mvc:interceptors>
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" /> <!-- 需放在拦截器中 -->
</mvc:interceptors>
- 创建视图并且导入<%@ taglib uri=“http://java.sun.com/jsp/jstl/fmt” prefix=“fmt”%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<fmt:message key="resource.describe" />
<fmt:message key="resource.oneself" />
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- start 使用message 标签配置需要显示的国际化文本, locale 对应国际化文件中对应的键的名称 -->
<a href="hello.action?locale=zh_CN">Chinese</a>
<a href="hello.action?locale=en_US">English</a>
</body>
</html>
14. 拦截器
- bean实现拦截器
package com.znsd.springmvc.expand;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class MyInterceptor implements HandlerInterceptor {
/**
* 进入目标方法之前调用
* 返回true:则继续调用后续的拦截器和目标方法
* 返回false:则不会调用后续的拦截器和目标方法
* 使用场景:权限控制、日志处理、事务...
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("FirstInterceptor.preHandle()");
return true;
}
/**
* 调用目标方法之后,在渲染页面之前调用
* 使用场景:
* 1.需要改变request对象中的值
* 2.需要修改modelAndView中的值
* 3.修改转向的视图
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor.postHandle()");
}
/**
* 渲染页面完成之后调用
* 使用场景:做一些销毁工作
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("FirstInterceptor.afterCompletion()");
}
}
- 自定义拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/handler/testInterceptor.action"/>
<bean class="com.znsd.springmvc.expand.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
15. 文件的上传与下载
- jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="handler/fileupload.action" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="上传" />
</form>
</body>
</html>
- handler
package com.znsd.springmvc.handler;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import javax.servlet.ServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
@Controller
@RequestMapping("/handler")
public class DemoHandler {
@RequestMapping("/fileupload")
public String fileupload(ServletRequest request, @RequestParam("file") MultipartFile file, Model model)
throws IOException {
if (!file.isEmpty()) {
String imageurl = saveFile(request, file);
model.addAttribute("imageurl", imageurl);
} else {
model.addAttribute("message", "请选择要上传的文件");
}
return "success";
}
// 下载
@RequestMapping("/downFile")
public ResponseEntity<byte[]> testdownFile(HttpSession session) throws IOException {
ServletContext servletContext = session.getServletContext();
InputStream in = servletContext.getResourceAsStream("downloads/down.txt");
byte[] bytes = FileCopyUtils.copyToByteArray(in);
HttpHeaders header = new HttpHeaders();
header.add("Content-Disposition", "attachment;filename=down.txt");
ResponseEntity<byte[]> entity = new ResponseEntity<byte[]>(bytes, header, HttpStatus.OK);
return entity;
}
private String saveFile(ServletRequest request, MultipartFile file) throws IOException {
// 获取文件的上传路径
String uploadPath = request.getServletContext().getRealPath("uploads");
System.out.println(uploadPath);
File uploadPathFile = new File(uploadPath);
if (!uploadPathFile.exists()) {
uploadPathFile.mkdirs();
}
// 获取文件名称
String filename = file.getOriginalFilename();
// 截取文件后缀
String fileext = filename.substring(filename.lastIndexOf("."));
// 生成新的随机文件名称
String newfileName = UUID.randomUUID() + fileext;
// 文件保存路径
File savePath = new File(uploadPath + "/" + newfileName);
// 上传文件
file.transferTo(savePath);
return "uploads/" + newfileName;
}
}
16. 异常的处理方式
- 配置xml
<!-- 配置使用SimpleMappingExceptionResolver来映射异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 给异常命名一个别名 -->
<property name="exceptionAttribute" value="ex"></property>
<property name="exceptionMappings">
<props>
<!-- 一定要异常的全类名。 表示出现异常,就跳转到error.jsp视图 -->
<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
</props>
</property>
</bean>
- @ExceptionHandler注解实现异常处理异常类
/**
* 全局异常处理类,在项目中推荐使用全局异常处理类去处理所有异常信息
* @author Administrator
*/
@ControllerAdvice
public class ExceptionHandlerAdvice {
/**
* 在项目总如果没有对异常有页面要求,那么一个异常页面就够了
* 有些项目需要对每一类型的异常都有对象异常页面,比如前台的异常处理、后台异常处理
* @param request
* @param response
* @param handler
* @param ex
* @return
*/
@ExceptionHandler(value = { NullPointerException.class, IndexOutOfBoundsException.class })
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
// 如果要将异常传递到视图中(jsp页面),必须使用ModelAndView来进行数据传递
// 不能使用Map形参的方式,否则会报错
System.out.println("ExceptionHandlerAdvice.resolveException()");
Map<String, Object> map = new HashMap<String, Object>();
map.put("ex", ex);
ModelAndView mv = new ModelAndView("error", map);
return mv;
}
}
- HandlerExceptionResolver 接口自定义异常处理器
@Component // 将自定义异常类装载到spring容器中
public class CustomeException implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
Map<String, Object> map = new HashMap<String, Object>();
if (ex instanceof NullPointerException) {
map.put("ex", ex);
return new ModelAndView("nullPointer", map); // 指定异常对应的视图页面
}
if (ex instanceof IndexOutOfBoundsException) {
return new ModelAndView("indexOutOf", map); // 指定异常对应的视图页面
}
return new ModelAndView("error", map);
}
}