SpringMVC

SpringMVC

概念

  • SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 Spring FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。
  • 使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring的 Spring MVC 框架或集成其他 MVC 开发框架,如 Struts1(现在一般不用),Struts2 等
  • SpringMVC 已经成为目前最主流的 MVC 框架之一,并且随着 Spring3.0 的发布,全面超越 Struts2,成为最优秀的 MVC 框架。
  • 它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful 编程风格的请求。

入门

执行步骤

  • 第一步:环境搭建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<properties>
<!--版本锁定-->
<spring.version>5.2.4.RELEASE</spring.version>
</properties>

<dependencies>
<!--sping ioc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring web-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring mvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

<!--servlet api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

<!--jsp-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
  • 第二步:在web.xml配置文件中核心控制器DispatcherServlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置Servlet的初始化参数 读取springmvc的配置文件,创建Spring容器-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--配置servlet 启动时加载对象-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
  • 第三步:编写springmvc.xml的配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<!--配置spring创建容器要扫描的包-->
<context:component-scan base-package="com.nogizaka"></context:component-scan>

<!--配置视图解析器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>

<!--配置spring开启注解mvc的支持-->
<mvc:annotation-driven></mvc:annotation-driven>

</beans>
  • 第四步:编写index.jsp和HelloController控制器类
  • 第五步:在WEB-INF目录下创建pages文件夹,编写success.jsp的成功页面
  • 第六步:启动Tomcat服务器,进行测试

执行流程

  1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象,
    就会加载springmvc.xml配置文件
  2. 开启了注解扫描,那么HelloController对象就会被创建
  3. 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解
    找到执行的具体方法
  4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
  5. Tomcat服务器渲染页面,做出响应

组件分析

  1. 前端控制器(DispatcherServlet);用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
  2. 处理器映射器(HandlerMapping):HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等
  3. 处理器(Handler):它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。
  4. 处理器适配器(HandlAdapter):通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
  5. 视图解析器(View Resolver):View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
  6. 视图(View):SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

<mvc:annotation-driven>说明

  • 在SpringMVC的各个组件中,处理器映射器处理器适配器视图解析器称为 SpringMVC 的三大组件。
  • 使用<mvc:annotation-driven>自动加载 RequestMappingHandlerMapping (处理映射器) 和RequestMappingHandlerAdapter(处理适配器),可用在SpringMVC.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 上面的标签相当于 如下配置-->
<!-- Begin -->
<!-- HandlerMapping -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- HadnlerExceptionResolvers -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"></bean>
<!-- End -->

@RequestMapping注解

  1. RequestMapping注解的作用是建立请求URL处理方法之间的对应关系
  2. RequestMapping注解可以作用在方法

    • 作用在类上:第一级的访问目录
    • 作用在方法上:第二级的访问目录
    • 细节:路径可以不编写/表示应用的根目录开始
    • 细节:${ pageContext.request.contextPath}也可以省略不写,但是路径上不能写 /
  3. RequestMapping的属性

    • path:指定请求路径的url
    • value :value属性和path属性是一样的
    • method: 指定该方法的请求方式
    • headers :发送的请求中必须包含的请求头
    • params :指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和配置的一模一样.
      • 例如:
        • params = {“accountName”},表示请求参数必须有 accountName
        • params = {“moeny!100”},表示请求参数中 money 不能是 100。

请求参数的绑定

绑定的机制

  • 绑定机制
    1. 表单提交的数据都是k=v格式的 username=haha&password=123
    2. SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
    3. 要求:提交表单的name参数的名称是相同的
  • 支持的数据类型
    1. 基本数据类型和字符串类型
    2. 实体类型(JavaBean)
    3. 集合数据类型(List、map集合等)

支持的数据类型

  • 基本数据类型:基本类型和String
    • 提交表单的name和参数的名称是相同的
    • 区分大小写
  • POJO类型参数:实体类以及关联的实体类
    • 提交表单的name和JavaBean中的属性名称需要一致
    • 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如:address.name
  • 数组和集合类型参数:包括List结构和Map结构的集合
    • JSP页面编写方式:list[0].属性

请求参数中文乱码

  • 在web.xml中配置Spring提供的过滤器类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--配置解决中文乱码的过滤器-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--指定字符集-->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
  • 注意如果出现控制台中文乱码,检查当前编码输出格式:System.out.println(System.getProperty("file.encoding"));

自定义类型转换器

  • 定义一个类,实现Converter接口,该接口有两个泛型
  • 在 spring 配置文件中配置类型转换器。
  • annotation-driven 标签中引用配置的类型转换服务
1
2
3
4
5
6
7
8
9
10
11
<!--配置自定义类型转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.nogizaka.utils.StringToDateConverter"></bean>
</set>
</property>
</bean>

<!--配置spring开启注解mvc的支持 添加类型转换器-->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>

使用 ServletAPI 对象作为方法参数

  • 直接写在Controller控制的方法参数中使用
1
2
3
4
5
6
7
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request,HttpServletResponse response,HttpSession session) {
System.out.println(request);
System.out.println(response);
System.out.println(session);
return "success";
}

常用注解

@RequestParam

  • 作用:把请求中指定名称的参数给控制器中的形参赋值。
  • 属性:
    • value:请求参数中的名称。
    • required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
  • 示例代码:
1
2
3
4
5
6
@RequestMapping(path="/hello")
public String sayHello(@RequestParam(value="username",required=false)String name) {
System.out.println("aaaa");
System.out.println(name);
return "success";
}

@RequestBody

  • 作用:用于获取请求体内容。直接使用得到是key=value&key=value..结构的数据。get请求方式不适用。
  • 属性:
    • required:是否必须有请求体。默认值是:true。当取值为true时,get请求方式会报错。如果取值为false,get请求得到是null
  • 示例代码:
1
2
3
4
5
6
@RequestMapping(path="/hello")
public String sayHello(@RequestBody String body) {
System.out.println("aaaa");
System.out.println(body);
return "success";
}

@ResponseBody

  • 作用:将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据
  • 注意:在使用此注解之后不会再走试图处理器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。

@PathVariable

  • 作用:拥有绑定url中的 的。例如:url中有/delete/{id},{id}就是占位符
  • 属性:
    • value:指定url中的占位符名称
  • Restful风格的URL
    • 请求路径一样,可以根据不同的请求方式去执行后台的不同方法
    • restful风格的URL优点
      • 结构清晰
      • 符合标准
      • 易于理解
      • 扩展方便
  • 示例代码:
1
2
3
4
5
@RequestMapping(path="/hello/{id}")
public String sayHello(@PathVariable(value="id") String id) {
System.out.println(id);
return "success";
}

@RequestHeader

  • 作用:获取指定请求头的值
  • 属性:
    • value:请求头的名称
  • 示例代码:
1
2
3
4
5
@RequestMapping(path="/hello")
public String sayHello(@RequestHeader(value="Accept") String header) {
System.out.println(header);
return "success";
}

@CookieValue

  • 作用:用于获取指定cookie的名称的值
  • 属性:
    • value:cookie的名称
  • 示例代码:
1
2
3
4
5
@RequestMapping(path="/hello")
public String sayHello(@CookieValue(value="JSESSIONID") String cookieValue) {
System.out.println(cookieValue);
return "success";
}

@ModelAttribute

  • 作用:
    • 出现在方法上:表示当前方法会在控制器方法执行前先执行
    • 出现在参数上:获取指定的数据给参数赋值
  • 应用场景:
    • 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据
  • 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
* 作用在方法,先执行
* @param name
* @return
*/
@ModelAttribute
public User showUser(String name) {
System.out.println("showUser执行了...");
// 模拟从数据库中查询对象
User user = new User();
user.setName("哈哈");
user.setPassword("123");
user.setMoney(100d);
return user;
} /
**
* 修改用户的方法
* @param cookieValue
* @return
*/
@RequestMapping(path="/updateUser")
public String updateUser(User user) {
System.out.println(user);
return "success";
}
//Model修饰方法不带返回值
@ModelAttribute
public void showModel(String username,Map<String,User> map) {
//模拟去数据库查询
User user = findUserByName(username);
System.out.println("执行了 showModel 方法"+user);
map.put("abc",user);
}
/**
* 模拟修改用户方法
* @param user
* @return
*/
@RequestMapping("/updateUser")
public String testModelAttribute(@ModelAttribute("abc")User user) {
System.out.println("控制器中处理请求的方法:修改用户:"+user);
return "success";
}

@SessionAttribute

  • 作用:用于多次执行控制器方法间参数共享,只能作用在类上
  • 属性:
    • value:指定存入属性的名称
  • Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap
  • 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Controller
@RequestMapping("/anno")
@SessionAttributes(value = {"msg"})//把msg=飞鸟存入到session域对象中
public class AnnoComtroller {

@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam(name = "name") String username){
System.out.println("执行了");
System.out.println(username);
return "success";
}

// 使用Model对象 将数据存入request域
@RequestMapping("/testSessionAttributes")
public String testSessionAttributes(Model model){
System.out.println("sessionAttributes执行了");
//底层会存储到Request域对象中
model.addAttribute("msg","飞鸟");
return "success";
}

// 获取session中的值
@RequestMapping("/getSessionAttributes")
public String getSessionAttributes(ModelMap modelMap){
System.out.println("getsessionAttributes执行了");
//底层会存储到request域对象中
Object msg = modelMap.get("msg");
System.out.println(msg);
return "success";
}

// 删除session中的值

@RequestMapping("/delSessionAttributes")
public String delSessionAttributes(SessionStatus status){
System.out.println("delsessionAttributes执行了");
//底层会存储到request域对象中
status.setComplete();
return "success";
}

响应数据和结果视图

返回值分类

String

  • Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。
  • 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 返回字符串
* @param model
* @return
*/
@RequestMapping("/testString")
public String testString(Model model){
System.out.println("testString方法执行了");
//模拟从数据库中获取数据
User user = new User();
user.setUname("斋藤飞鸟");
user.setUage("20");
model.addAttribute("user",user);
return "success";
}

Void

  • 如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。
  • 默认会跳转到@RequestMapping(value="/initUpdate") initUpdate的页面。
  • 可以使用请求转发或者重定向或者直接响应跳转到指定的页面
  • 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 返回void
* 默认跳转testVoid.jsp
* 请求转发一次请求,不用编写项目的名称
* @param
*/
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("testVoid方法执行了");
//编写请求转发的程序
//request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);

// 编写重定向
//response.sendRedirect(request.getContextPath()+"/index.jsp");

// 设置中文乱码
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 直接进行响应
response.getWriter().print("你好");
return;
}

ModelAndView

  • ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图
  • 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 返回ModelAndView
* @return
*/
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
// 创建ModelAndView对象,由spring mvc提供
ModelAndView mv = new ModelAndView();
//模拟从数据库中获取数据
User user = new User();
user.setUname("白石麻衣");
user.setUage("26");
//把user对象存储到mv对象中,也会把user对象存入request域对象中
mv.addObject("user",user);
// 跳转到哪个页面
mv.setViewName("success");
return mv;
}

转发和重定向

  • 使用forward关键字进行请求转发
  • 使用redirect关键字进行重定向
  • 示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
      /**
    * 使用关键字的方式进行转发或重定向
    * @return
    */
    @RequestMapping("/testForwardOrRedirect")
    public String testForwardOrRedirect(){
    System.out.println("testForwardOrRedirect方法执行了");

    //请求的转发
    return "forward:/WEB-INF/pages/success.jsp";

    //重定向,框架默认添加了项目名称request.getContextPath()
    return "redirect:/index.jsp";
    }

ResponseBody响应json数据

  • DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置

  • 使用webjars,进行如下配置(WebJars是打包到JAR(Java Archive)文件中的客户端Web库(例如jQuery和Bootstrap)。)

1
2
3
4
5
<!--前端控制器 设置静态资源不过滤-->
<mvc:default-servlet-handler/>
<!--对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。-->
<!--<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/>-->
<!--<mvc:resources mapping="/webjars/**" location="/webjars/"/>-->
  • location:表示webapp目录下(即服务器根目录)的static包下的所有文件
  • mapping:表示以/static开头的所有请求路径,如/static/a或者/static/a/b
  • 作用:DispatcherServlet不会拦截以/static开头的所有请求路径,并当作静态资源交由Servlet处理;
1
2
3
4
<!-- 设置静态资源不过滤 -->
<mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 -->
<mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 -->
<mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->

异步请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<%--引入jquery资源--%>
<script src="webjars/jquery/3.4.1/jquery.min.js"></script>

<script>
// 页面加载 绑定单击事件
$(function () {
$("#btn").click(function () {
/*alert("hello btn!!!!!");*/
$.ajax({
//编写json格式,设置属性和值
url:"user/testAjax",
contentType:"application/json;charset=UTF-8",
data:'{"uname":"乃木坂","uage":8}',
dataType:"json",
type:"post",
success:function (data) {
// data服务器端响应的json数据,进行解析
alert(data);
alert(data.uname);
alert(data.uage);
}
});
});
});
</script>

使用@RequestBody注解把json的字符串转换为javabean对象

  • json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--jackson将json数据封装到javabean-->
<!--spring默认用MappingJacksonHttpMessageConverter对json数据转换-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.10.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.3</version>
</dependency>

使用@ResponseBody注解把javabean对象转换为json字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 模拟异步请求和响应
*/
@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user){
System.out.println("testAjax方法执行了。。。");
/*客户端发送ajax请求,传json字符串,后端把json字符串封装到user对象中*/
System.out.println(user);
/*响应。模拟查询数据库*/
user.setUname("飞鸟");
user.setUage("20");
return user;
}

SpringMVC实现文件上传

文件上传前提

  • form表单的enctype(表单请求正文的类型)取值必须是:multipart/form-data(默认值是:application/x-www-form-urlencoded)
  • method属性取值必须是:POST
  • 提供一个文件选择域:<input type="file"/>
  • 借助第三方组件实现文件上传:Commons-fileupload

传统方式文件上传

  • 使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:Commons-fileupload 和commons-io。commons-io 不属于文件上传组件的开发 jar 文件,但Commons-fileupload 组件从 1.1 版本开始,它工作时需要 commons-io 包的支持。

  • 导入文件上传的Commons组件

1
2
3
4
5
6
7
8
9
10
11
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
  • 文件上传
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 文件上传
*/
@RequestMapping("/testFileUpload")
public String testFileUpload(HttpServletRequest request) throws Exception {
System.out.println("testFileUpload方法执行了。。。");

// 使用fileupload组件完成上传
// 指定上传位置
String path = request.getSession().getServletContext().getRealPath("/uploads");
// 判断 该路径是否存在
File file = new File(path);
if(!file.exists()){
//创建该文件夹
file.mkdirs();
System.out.println("文件夹创建成功");
}
//解析request对象,获取上传文件项
//创建磁盘文件项工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//解析request
List<FileItem> items = upload.parseRequest(request);
//遍历
for (FileItem item : items) {
// 进行判断,当前item对象是否是上传文件项
if(item.isFormField()){
//说明普通表单项
}else {
//说明上传文件项
// 获取上传文件名称
String name = item.getName();
// 把文件的名称设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
name=uuid+"_"+name;
// 完成文件上传
item.write(new File(path,name));
// 删除临时文件
item.delete();
}
}
System.out.println("文件上传成功");
return "success";
}

SpringMVC传统方式文件上传

  • SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的name属性名称相同。

  • 原理:上传->前端控制器->文件解析器->前端控制器->Controller文件上传方法(参数绑定MultipartFile)

  • 配置文件解析器

1
2
3
4
<!--配置文件解析器对象 要求Id必须是multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10*1024*1024"/>
</bean>
  • 代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* springmvc文件上传
*/
@RequestMapping("/SpringFileUpload")
public String SpringFileUpload(HttpServletRequest request,MultipartFile upload) throws Exception {
System.out.println("springmvc文件上传。。");
// 指定上传位置
String path = request.getSession().getServletContext().getRealPath("/uploads");
// 判断 该路径是否存在
File file = new File(path);
if(!file.exists()){
//创建该文件夹
file.mkdirs();
System.out.println("文件夹创建成功");
}

//获取上传文件名称
String filename = upload.getOriginalFilename();
// 把文件的名称设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename=uuid+"_"+filename;
// 完成文件上传
upload.transferTo(new File(path,filename));
return "success";
}

SpringMVC跨服务器方式文件上传

  • 在实际开发中,我们会有很多处理不同功能的服务器
    • 应用服务器:负责部署我们的应用
    • 数据库服务器:运行我们的数据库
    • 缓存和消息服务器:负责处理大并发访问的缓存和消息
    • 文件服务器:负责存储用户上传文件的服务器。

SpringMVC的异常处理

  • 异常处理思路
    • Controller调用Service,Service调用Dao,异常都是向上抛出的,最终由DispatcherServlet招异常处理器进行异常的处理
  • SpringMVC的异常处理

异常处理

  • 第一步:自定义异常类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Created with IntelliJ IDEA.
*
* @author: MR.WU
* @date: 2020/4/2 17:16
* @desc: 自定义异常类
*/
public class MyException extends Exception{

// 存储提示信息
private String message;

public MyException(String message) {
this.message = message;
}

@Override
public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}
}
  • 第二步:自定义异常处理器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* Created with IntelliJ IDEA.
*
* @author: MR.WU
* @date: 2020/4/2 17:22
* @desc: 异常处理器
*/
public class MyExceptionResolver implements HandlerExceptionResolver {

/**
* 处理异常业务逻辑
* @param httpServletRequest
* @param httpServletResponse
* @param o
* @param e
* @return
*/
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
// 获取异常对象
MyException me = null;
if(e instanceof MyException){
e = (MyException)me;
}else {
e = new MyException("系统正在维护");
}
// 创建ModelAndView对象
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg",e.getMessage());
mv.setViewName("error");
return mv;
}
}
  • 第三步:配置异常处理器
1
2
<!--配置异常处理器-->
<bean id="myExceptionResolver" class="com.nogizaka.exception.MyExceptionResolver"></bean>

SpringMVC中的拦截器

  • Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
  • 过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。
  • 拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
  • 过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。
  • 拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦截的。
  • 自定义拦截器:实现HandlerInterceptor接口

拦截器的实现

  • 第一步:编写拦截器类:实现HandlerInterceptor接口

    • preHandle方法是controller方法执行前拦截的方法
      • 可以使用request或者response跳转到指定的页面
      • return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
      • return false不放行,不会执行controller中的方法。
    • postHandle是controller方法执行后执行的方法,在JSP视图执行前。
      • 可以使用request或者response跳转到指定的页面
      • 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。
    • afterCompletion方法是在JSP执行后执行
      • request或者response不能再跳转页面了
  • 第二步:配置拦截器

1
2
3
4
5
6
7
8
9
10
11
12
<!--配置拦截器-->
<mvc:interceptors>
<!--配置拦截器-->
<mvc:interceptor>
<!--要拦截的具体方法-->
<mvc:mapping path="/user/*"/>
<!--不要拦截的方法
<mvc:exclude-mapping path=""/>-->
<!--配置拦截器对象-->
<bean class="com.nogizaka.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
Knowledge is priceless, thanks for your support !