项目管理与SSM框架——SpringMVC

SpringMVC



一、SpringMVC入门

1.SpringMVC简介

MVC模型
MVC全称Model View Controller,是一种设计创建Web应用程序的模式。这三个单词分别代表Web应用程序的三个部分:

Model(模型):指数据模型。用于存储数据以及处理用户请求的业务逻辑。在Web应用中,JavaBean对象,业务模型等都属于Model。

View(视图):用于展示模型中的数据的,一般为jsp或html文件。

Controller(控制器):是应用程序中处理用户交互的部分。接受视图提出的请求,将数据交给模型处理,并将处理后的结果交给视图显示。

在这里插入图片描述

SpringMVC
SpringMVC是一个基于MVC模式的轻量级Web框架,是Spring框架的一个模块,和Spring可以直接整合使用。SpringMVC代替了Servlet技术,它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口。

2.SpringMVC入门案例

接下来我们编写一个SpringMVC的入门案例

1.使用maven创建web项目,补齐包结构。

2.引入相关依赖和tomcat插件

1<dependencies>
2    <!-- Spring核心模块 -->
3    <dependency>
4        <groupId>org.springframework</groupId>
5        <artifactId>spring-context</artifactId>
6        <version>5.2.12.RELEASE</version>
7    </dependency>
8    <!-- SpringWeb模块 -->
9    <dependency>
10        <groupId>org.springframework</groupId>
11        <artifactId>spring-web</artifactId>
12        <version>5.2.12.RELEASE</version>
13    </dependency>
14    <!-- SpringMVC模块 -->
15    <dependency>
16        <groupId>org.springframework</groupId>
17        <artifactId>spring-webmvc</artifactId>
18        <version>5.2.12.RELEASE</version>
19    </dependency>
20    <!-- Servlet -->
21    <dependency>
22        <groupId>javax.servlet</groupId>
23        <artifactId>servlet-api</artifactId>
24        <version>2.5</version>
25        <scope>provided</scope>
26    </dependency>
27    <!-- JSP -->
28    <dependency>
29        <groupId>javax.servlet.jsp</groupId>
30        <artifactId>jsp-api</artifactId>
31        <version>2.0</version>
32        <scope>provided</scope>
33    </dependency>
34</dependencies>
35
36<build>
37    <plugins>
38        <!-- tomcat插件 -->
39        <plugin>
40            <groupId>org.apache.tomcat.maven</groupId>
41            <artifactId>tomcat7-maven-plugin</artifactId>
42            <version>2.1</version>
43            <configuration>
44                <port>8080</port>
45                <path>/</path>
46                <uriEncoding>UTF-8</uriEncoding>
47                <server>tomcat7</server>
48                <systemProperties>
49                    <java.util.logging.SimpleFormatter.format>%1$tH:%1$tM:%1$tS %2$s%n%4$s: %5$s%6$s%n
50                    </java.util.logging.SimpleFormatter.format>
51                </systemProperties>
52            </configuration>
53        </plugin>
54    </plugins>
55</build>

3.在web.xml中配置前端控制器DispatcherServlet。

1<web-app>
2    <display-name>Archetype Created Web Application</display-name>
3    <!--SpringMVC前端控制器,本质是一个Servlet,接收所有请求,在容器启动时就会加载-->
4    <servlet>
5        <servlet-name>dispatcherServlet</servlet-name>
6        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
7        <init-param>
8            <param-name>contextConfigLocation</param-name>
9            <param-value>classpath:springmvc.xml</param-value>
10        </init-param>
11        <load-on-startup>1</load-on-startup>
12    </servlet>
13    <servlet-mapping>
14        <servlet-name>dispatcherServlet</servlet-name>
15        <url-pattern>/</url-pattern>
16    </servlet-mapping>
17</web-app>

4.编写SpringMVC核心配置文件springmvc.xml,该文件和Spring配置文件写法一样。

1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3       xmlns:mvc="http://www.springframework.org/schema/mvc"
4       xmlns:context="http://www.springframework.org/schema/context"
5       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6       xsi:schemaLocation="
7        http://www.springframework.org/schema/beans
8        http://www.springframework.org/schema/beans/spring-beans.xsd
9        http://www.springframework.org/schema/mvc
10        http://www.springframework.org/schema/mvc/spring-mvc.xsd
11        http://www.springframework.org/schema/context
12        http://www.springframework.org/schema/context/spring-context.xsd">
13
14    <!-- 扫描包 -->
15    <context:component-scan base-package="com.package"/>
16
17    <!-- 开启SpringMVC注解的支持 -->
18    <mvc:annotation-driven/>
19
20</beans>

5.编写控制器

1@Controller
2public class MyController1 {
    
    
3    // 该方法的访问路径是/c1/hello1
4    @RequestMapping("/c1/hello1")
5    public void helloMVC(){
    
    
6        System.out.println("hello SpringMVC!");
7    }
8}

3.SpringMVC执行流程

在这里插入图片描述
SpringMVC的组件
DispatcherServlet:前端控制器,接受所有请求,调用其他组件。
HandlerMapping:处理器映射器,根据配置找到方法的执行链。
HandlerAdapter:处理器适配器,根据方法类型找到对应的处理器。
ViewResolver:视图解析器,找到指定视图。

组件的工作流程
1.客户端将请求发送给前端控制器。
2.前端控制器将请求发送给处理器映射器,处理器映射器根据路径找到方法的执行链,返回给前端控制器。
3.前端控制器将方法的执行链发送给处理器适配器,处理器适配器根据方法类型找到对应的处理器。
4.处理器执行方法,将结果返回给前端控制器。
5.前端控制器将结果发送给视图解析器,视图解析器找到视图文件位置。
6.视图渲染数据并将结果显示到客户端。

二、SpringMVC参数获取

1.封装为简单数据类型

在Servlet中我们通过request.getParameter(name)获取请求参数。该方式存在两个问题:

请求参数较多时会出现代码冗余。
与容器紧耦合。

而SpringMVC支持参数注入的方式用于获取请求数据,即将请求参数直接封装到方法的参数当中。用法如下:

1.编写控制器方法

1// 获取简单类型参数
2@RequestMapping("/c1/param1")
3public void simpleParam(String username,int age){
    
    
4    System.out.println(username);
5    System.out.println(age);
6}

2.访问该方法时,请求参数名和方法参数名相同,即可完成自动封装。

http://localhost:8080/c1/param1?username=cc&age=8

2.封装为对象类型

SpringMVC支持将参数直接封装为对象,写法如下:

封装单个对象

1.编写实体类

1public class Student {
    
    
2    private int id;
3    private String name;
4    private String sex;
5    // 省略getter/setter/tostring
6}

2.编写控制器方法

1// 获取对象类型参数
2@RequestMapping("/c1/param2")
3public void objParam(Student student){
    
    
4    System.out.println(student);
5}

3.访问该方法时,请求参数名和方法参数的属性名相同,即可完成自动封装。

http://localhost:8080/c1/param2?id=233&name=bear&sex=female

封装关联对象

1.编写实体类

1public class Address {
    
    
2    private String info; //地址信息
3    private String postcode; //邮编
4    // 省略getter/setter/tostring
5}
6public class Student {
    
    
7    private int id;
8    private String name;
9    private String sex;
10    private Address address; // 地址对象
11    // 省略getter/setter/tostring
12}

2.编写控制器方法

1// 获取关联对象类型参数
2@RequestMapping("/c1/param3")
3public void objParam2(Student student){
    
        
4    System.out.println(student);
5}

3.访问该方法时,请求参数名和方法参数的属性名相同,即可完成自动封装。

http://localhost:8080/c1/param3?id=1&name=xiongmao&sex=female&address.info=chengdu&address.postcode=030000

我们也可以使用表单发送带有参数的请求:

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<html>
3 <head>
4     <title>表单提交</title>
5 </head>
6 <body>
7     <form action="/c1/param3" method="post">
8         id:<input name="id">
9         姓名:<input name="name">
10         性别:<input name="sex">
11         住址:<input name="address.info">
12         邮编:<input name="address.postcode">
13         <input type="submit">
14     </form>
15 </body>
16</html>

3.封装为集合类型

SpringMVC支持将参数封装为List或Map集合,写法如下:

封装为List集合

封装为简单数据类型集合

1.编写控制器方法

1// 绑定简单数据类型List参数,参数前必须添加@RequestParam注解
2@RequestMapping("/c1/param4")
3public void listParam(@RequestParam List<String> users){
    
     
4    System.out.println(users);
5}

该方式也可以绑定数组类型:

1@RequestMapping("/c1/param5")
2public void listParam2(@RequestParam String[] users){
    
     
3    System.out.println(users[0]); 
4    System.out.println(users[1]);
5}

2.请求的参数写法

http://localhost:8080/c1/param4?users=bj&users=cd

封装为对象类型集合

SpringMVC不支持将参数封装为对象类型的List集合,但可以封装到有List属性的对象中。

1.编写实体类

1public class Student {
    
    
2    private int id;
3    private String name;
4    private String sex;
5    private List<Address> address; // 地址集合
6    // 省略getter/setter/tostring
7}

2.编写控制器方法

1// 对象中包含集合属性
2@RequestMapping("/c1/param6")
3public void listParam3(Student student){
    
    
4    System.out.println(student);
5}

3.请求的参数写法

http://localhost:8080/c1/param6?id=1&name=qiqi&sex=female&address[0].info=bj&address[0].postcode=100010&address[1].info=sh&address[1].postcode=100011

封装为Map集合

同样,SpringMVC要封装Map集合,需要封装到有Map属性的对象中。

1.编写实体类

1public class Student {
    
    
2    private int id;
3    private String name;
4    private String sex;
5    private Map<String,Address> address; // 地址集合
6    // 省略getter/setter/tostring
7}

2.编写控制器方法

1// 对象中包含Map属性
2@RequestMapping("/c1/param7")
3public void mapParam(Student student){
    
       
4    System.out.println(student);
5}

3.请求的参数写法

http://localhost:8080/c1/param7?id=1&name=gtq&sex=female&address[‘one’].info=bj&address[‘one’].postcode=100010&address[‘two’].info=sh&address[‘two’].postcode=100011

4.使用Servlet原生对象获取参数

SpringMVC也支持使用Servlet原生对象,在方法参数中定义HttpServletRequestHttpServletResponseHttpSession等类型的参数即可直接在方法中使用。

1// 使用Servlet原生对象
2@RequestMapping("/c1/param8")
3public void servletParam(HttpServletRequest request, HttpServletResponse response, HttpSession session){
    
      
4    // 原生对象获取参数                                  
5    System.out.println(request.getParameter("name")); 
6    System.out.println(response.getCharacterEncoding());    
7    System.out.println(session.getId());
8}

访问该方法即可:http://localhost:8080/c1/param8?name=biubiu

5.自定义参数类型转换器

前端传来的参数全部为字符串类型,SpringMVC使用自带的转换器将字符串参数转为需要的类型。如:

1// 获取简单类型参数
2@RequestMapping("/c1/param1")
3public void simpleParam(String username,int age){
    
     
4    System.out.println(username);    
5    System.out.println(age);
6}

请求路径:http://localhost:8080/c1/param1?username=bz&age=10

但在某些情况下,无法将字符串转为需要的类型,如:

1@RequestMapping("/c1/param9")
2public void dateParam(Date birthday){
    
      
3    System.out.println(birthday);
4}

由于日期数据有很多种格式,SpringMVC没办法把所有格式的字符串转换成日期类型。比如参数格式为birthday=2025-01-01时,SpringMVC就无法解析参数。此时需要自定义参数类型转换器。

1.定义类型转换器类,实现Converter接口

1// 类型转换器必须实现Converter接口,两个泛型代表转换前的类型,转换后的类型
2public class DateConverter implements Converter<String, Date> {
    
    
3    /**
4     * 转换方法
5     * @param source 转换前的数据
6     * @return 转换后的数据
7     */
8    @Override
9    public Date convert(String source) {
    
    
10        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
11        Date date = null;
12        try {
    
    
13            date = sdf.parse(source);
14        } catch (ParseException e) {
    
    
15            e.printStackTrace();
16        }
17        return date;
18    }
19}

2.注册类型转换器对象

1<!-- 配置转换器工厂 -->
2<bean id="dateConverter" class="org.springframework.context.support.ConversionServiceFactoryBean">
3    <!-- 转换器集合 -->
4    <property name="converters">
5        <set>
6            <!-- 自定义转换器 -->
7            <bean class="com.package.converter.DateConverter"></bean>
8        </set>
9    </property>
10</bean
11    
12<!-- 使用转换器工厂 -->
13<mvc:annotation-driven conversion-service="converterFactory"></mvc:annotation-driven>

此时再访问http://localhost:8080/c1/param9?birthday=2025-01-01时,SpringMVC即可将请求参数封装为Date类型的参数。

6.编码过滤器

在传递参数时,tomcat8以上能处理get请求的中文乱码,但不能处理post请求的中文乱码

1.编写jsp表单

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<html>
3    <head>
4        <title>编码过滤器</title>
5    </head>
6    <body>
7        <form action="/cn/code" method="post">
8            姓名:<input name="username">
9            <input type="submit">
10        </form>
11    </body>
12</html>

2.编写控制器方法

1@RequestMapping("/cn/code")
2public void code(String username){
    
    
3    System.out.println(username);
4}

SpringMVC提供了处理中文乱码的过滤器,在web.xml中配置该过滤器即可解决中文乱码问题:

1<!--SpringMVC中提供的字符编码过滤器,放在所有过滤器的最上方-->
2<filter>
3    <filter-name>encFilter</filter-name>
4    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
5    <init-param>
6        <param-name>encoding</param-name>
7        <param-value>utf-8</param-value>
8    </init-param>
9</filter>
10<filter-mapping>
11    <filter-name>encFilter</filter-name>
12    <url-pattern>/*</url-pattern>
13</filter-mapping>

三、SpringMVC处理响应

1.配置视图解析器

SpringMVC默认情况下会在控制器执行完成后跳转到视图页面,视图解析器能找到相应的视图,之前的404异常就是由于没有配置视图解析器导致找不到视图。

在SpringMVC中提供了13个视图解析器,用于支持不同的视图技术。InternalResourceViewResolver是SpringMVC的默认视图解析器,用来解析JSP视图。

1<!-- 视图解析器 -->
2<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
3    <!-- 视图前缀 -->
4    <property name="prefix" value="/" />
5    <!-- 视图后缀 -->
6    <property name="suffix" value=".jsp" />
7</bean>

2.控制器方法的返回值

我们可以通过控制器方法的返回值设置跳转的视图,控制器方法支持以下返回值类型:

返回值为void

此时会跳转到名字是 前缀+方法路径名+后缀 的jsp页面

1.编写控制器方法

1// 路径是helloMVC,方法执行完后会跳转到/helloMVC.jsp
2@RequestMapping("/helloMVC")
3public void helloMVC(){
    
    
4    System.out.println("hello SpringMVC!");
5}

2.编写helloMVC.jsp

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<html>
3    <head>
4        <title>MVC</title>
5    </head>
6    <body>
7        <h1>欢迎来到SpringMVC</h1>
8    </body>
9</html>

返回值为String

此时会跳转到名字是 前缀+返回值+后缀 的jsp页面

编写控制器方法

1// 返回值为String
2@RequestMapping("/c2/hello1")
3public String helloMVC1(){
    
    
4    System.out.println("hello SpringMVC!");
5    // 方法执行完后会跳转到/helloMVC.jsp
6    return "helloMVC";
7}

返回值为ModelAndView

这是SpringMVC提供的对象,该对象可以向request域设置数据并指定跳转的页面。该对象中包含Model对象和View对象。

Model:向request域中设置数据。
View:指定跳转的页面。

1.编写控制器方法

1// 返回值为ModelAndView
2@RequestMapping("/c2/hello2")
3public ModelAndView useMAV(){
    
    
4    System.out.println("返回值类型为ModelAndView");
5    // 1.创建ModelAndView对象
6    ModelAndView modelAndView = new ModelAndView();
7    // 2.获取Model对象,本质是一个Map
8    Map<String, Object> model = modelAndView.getModel();
9    // 3.使用Model对象向request域设置数据
10    model.put("name","小可爱");
11    // 4.使用View对象设置跳转的路径为/xiaokeai.jsp
12    modelAndView.setViewName("xiaokeai");
13    return modelAndView;
14}

2.编写jsp页面

1<%@ page contentType="text/html;charset=UTF-8" language="java"%>
2<html>
3    <head>
4        <title>可爱</title>
5    </head>
6    <body>
7        <h1>你好!${
    
    requestScope.name}</h1>
8    </body>
9</html>

3.修改web.xml命名空间,让jsp页面默认支持el表达式

1<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
2         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
4                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
5         version="3.1">
6</web-app>

3.request域设置数据

当控制器返回值为ModelAndView时我们可以向request域设置数据,我们还有以下方法可以向request域设置数据:

使用原生的HttpServletRequest

1@RequestMapping("/c2/hello3")
2public String setRequestModel(HttpServletRequest request){
    
    
3    request.setAttribute("username","xiaotaoqi");
4    return "xiaokeai";
5}

使用Model、ModelMap

SpringMVC提供了Model接口和ModelMap类,控制器方法添加这两个类型的参数,使用该参数设置数据,该数据就会存到request域中。

1@RequestMapping("/c2/hello4")
2public String setRequestModel2(Model model, ModelMap modelMap){
    
    
3    // 使用Model将数据存入request域
4    // model.addAttribute("username","尚学堂");
5    // 使用ModelMap将数据存入request域
6    modelMap.addAttribute("username","xiaotaoqi");
7    return "xiaokeai";
8}

使用Map集合

Model接口底层就是一个Map集合,我们可以给控制器方法设置Map类型的参数,向Map中添加键值对,数据也会存到request域中。

1@RequestMapping("/c2/hello5")
2public String setRequestModel3(Map map){
    
    
3    map.put("username","xiaotaoqi");
4    return "xiaokeai";
5}

4.session域设置数据

Session作用域表示在当前会话中有效。在SpringMVC中对于Session作用域传值,只能使用HttpSession对象来实现。

1.编写控制器方法

1@RequestMapping("/c2/hello6")
2public String setSeesionModel(HttpSession session){
    
    
3    session.setAttribute("address","beijing");
4    return "xiaokeai";
5}

2.编写jsp页面

1<%@ page contentType="text/html;charset=UTF-8" language="java"%>
2<html>
3    <head>
4        <title>可爱</title>
5    </head>
6    <body>
7        <h1>你好!${
    
    requestScope.name}</h1>
8        <h1>地址是!${
    
    sessionScope.address}</h1>
9    </body>
10</html>

5.context域设置数据

context作用域表示在整个应用范围都有效。在SpringMVC中对context作用域传值,只能使用ServletContext对象来实现。但是该对象不能直接注入到方法参数中,需要通过HttpSession对象获取。

1.编写控制器方法

1@RequestMapping("/c2/hello7")
2public String setContextModel(HttpSession session){
    
    
3    ServletContext servletContext = session.getServletContext();
4    servletContext.setAttribute("age",10);
5    return "xiaokeai";
6}

2.编写jsp页面

1<%@ page contentType="text/html;charset=UTF-8" language="java"%>
2<html>
3    <head>
4        <title>可爱</title>
5    </head>
6    <body>
7        <h1>你好!${
    
    requestScope.name}</h1>
8        <h1>地址是!${
    
    sessionScope.address}</h1>
9        <h1>年纪是!${
    
    applicationScope.age}</h1>
10    </body>
11</html>

6.请求转发&重定向

之前的案例,我们发现request域中的值可以传到jsp页面中,也就是通过视图解析器跳转到视图的底层是请求转发。

如果我们跳转时不想使用视图解析器,可以使用原生HttpServletRequest进行请求转发或HttpServletResponse进行重定向:

1@RequestMapping("/c2/hello8")
2public void myForward1(HttpServletRequest request, HttpServletResponse response) throws Exception{
    
    
3    request.setAttribute("name","daimubai");
4    // 请求转发
5    //        request.getRequestDispatcher("/c2/hello9").forward(request,response);
6    // 原生重定向
7    response.sendRedirect("/c2/hello9");
8}
9
10@RequestMapping("/c2/hello9")
11public void myForward2(HttpServletRequest request){
    
    
12    System.out.println("hello");
13    System.out.println(request.getAttribute("name"));
14}

SpringMVC还提供了一种更简单的请求转发和重定向的写法:

1@RequestMapping("/c2/hello10")
2public String myForward3(HttpServletRequest request){
    
    
3    request.setAttribute("name","tangsan");
4    // 请求转发
5    return "forward:/c2/hello9";
6    // 重定向
7    // return "redirect:/c2/hello9";
8}

四、SpringMVC注释

1.@Controller

作用:标记控制器,将控制器交给Spring容器管理。

位置:类上方

2.@RequestMapping

作用:给控制器方法设置请求路径

位置:方法或类上方。用于类上,表示类中的所有控制器方法都是以该地址作为父路径。

属性:

value/path:请求路径
method:指定请求方式
params:规定必须发送的请求参数
headers:规定请求必须包含的请求头

1@Controller
2@RequestMapping("/c3")
3public class MyController3 {
    
    
4     /*
5        访问路径为 /c3/annotation1
6        支持post和get请求
7        请求时必须带有age参数
8        请求时必须带有User-agent请求头
9     */
10    @RequestMapping(path = "/annotation1",method = {
    
    RequestMethod.GET,RequestMethod.POST},params = {
    
    "age"},headers = {
    
    "User-agent"})
11    public String annotation1(String username){
    
    
12        System.out.println(username);
13        return "xiaokeai";
14    }
15}

3.@RequestParam

作用:在控制器方法中获取请求参数

位置:方法参数前

属性:

name:指定请求参数名称
defaultValue: 为参数设置默认值
required:设置是否是必须要传入的参数

1/*
2    定义请求的参数名为username,默认值为sxt,不是必须的参数
3 */
4@RequestMapping("/annotation2")
5public String annotation2(@RequestParam(name = "username",defaultValue = "cute",required = false) String name){
    
    
6    System.out.println(name);
7    return "xiaokeai";
8}

请求URL的写法:http://localhost:8080/c3/annotation2?username=cool

4.@RequestHeader

@RequestHeader

作用:在控制器方法中获取请求头数据

位置:方法参数前

5.@CookieValue

@CookieValue

作用:在控制器方法中获取Cookie数据

位置:方法参数前

1/*
2        获取User-Agent请求头
3        获取JSESSIONID的Cookie值
4     */
5@RequestMapping("/annotation3")
6public String annotation3(@RequestHeader("User-Agent") String userAgent, @CookieValue("JSESSIONID") String jSessionId){
    
    
7    System.out.println(userAgent);
8    System.out.println(jSessionId);
9    return "xiaokeai";
10}

6.@SessionAttributes

作用:将Model模型中的数据存到session域中

位置:类上方

1@Controller
2@RequestMapping("/c4")
3// 将模型中的name数据保存到session中
4@SessionAttributes("name")
5public class MyController4 {
    
    
6    @RequestMapping("/t1")
7    public String t1(Model model){
    
    
8        // model中保存name数据
9        model.addAttribute("name","Jack");
10        return "xiaokeai";
11    }
12
13    @RequestMapping("/t2")
14    public String t2(HttpSession session){
    
    
15        // 从session中获取name数据
16        System.out.println(session.getAttribute("name"));
17        return "xiaokeai";
18    }
19}

7.@ModelAttribute

作用1:设置指定方法在控制器其他方法前执行

位置:方法上方

1@Controller
2@RequestMapping("/c5")
3public class MyController5 {
    
    
4    @ModelAttribute
5    public void before(){
    
    
6        System.out.println("前置方法");
7    }
8
9    @RequestMapping("/t1")
10    public String t1(){
    
    
11        System.out.println("t1");
12        return "xiaokeai";
13    }
14}
15

作用2:从Model模型中获取数据给参数赋值

位置:方法参数前

1@Controller
2@RequestMapping("/c6")
3public class MyController6 {
    
    
4    // 前置方法向Model中设置数据
5    @ModelAttribute
6    public void before(Model model){
    
    
7        model.addAttribute("name","小猪猪");
8    }
9
10    // 该参数不是从请求中获取,而是从Model中获取
11    @RequestMapping("/t1")
12    public String t1(@ModelAttribute("name") String name){
    
    
13        System.out.println(name);
14        return "xiaokeai";
15    }
16}

8.Restful风格支持

在这里插入图片描述
RESTful风格介绍

RESTful风格是一种URL路径的设计风格。在RESTful风格的URL路径中,网络上的任意数据都可以看成一个资源,它可以是一段文本、一张图片,也可以是一个Java对象。而每个资源都会占据一个网络路径,无论对该资源进行增删改查,访问的路径是一致的。

传统URL:

查找id为1的学生:
http://localhost:8080/student/findById?id=30

删除id为1的学生:
http://localhost:8080/student/deleteById?id=30

RESTful风格URL:

查找id为30的学生:
http://localhost:8080/student/30
删除id为30的学生:
http://localhost:8080/student/30

那么如何区分对该资源是哪一种操作?
通过请求方式不同,判断进行的是什么操作。

访问RESTful风格的URL一共有四种请求方式:

GET请求:查询操作
POST请求:新增操作
DELETE请求:删除操作
PUT请求:修改操作

RESTful风格URL:

查找id为30的学生:
http://localhost:8080/student/30 GET方式请求
删除id为30的学生:
http://localhost:8080/student/30 DELETE方式请求

RESTful风格的优点:

结构清晰、符合标准、易于理解、扩展方便。

@PathVariable

作用:在RESTful风格的URL中获取占位符的值

位置:方法参数前

属性:

value:获取哪个占位符的值作为参数值,如果占位符和参数名相同,可以省略该属性。

1@Controller
2@RequestMapping("/student")
3// 模拟学生的增删改查控制器
4public class StudentController {
    
    
5    // 路径中的{id}表示占位符,最后会封装到方法的参数中使用
6    // 删除学生
7    @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
8    public String deleteStudent(@PathVariable("id") int id){
    
    
9        System.out.println("删除id为"+id+"的学生");
10        return "xiaokeai";
11    }
12
13    // 如果占位符和参数名相同,可以省略@PathVariable的value属性
14    // 根据id查询学生
15    @RequestMapping(value = "/{id}",method = RequestMethod.GET)
16    public String findStudentById(@PathVariable int id){
    
    
17        System.out.println(id);
18        System.out.println("根据id查询学生");
19        return "xiaokeai";
20    }
21
22    // 新增学生
23    @RequestMapping(value = "/{id}",method = RequestMethod.POST)
24    public String addStudent(@PathVariable int id, Student student){
    
    
25        System.out.println(id);
26        System.out.println(student);
27        System.out.println("新增学生");
28        return "xiaokeai";
29    }
30
31    // 修改学生
32    @RequestMapping(value = "/{id}",method = RequestMethod.PUT)
33    public String updateStudent(@PathVariable int id, Student student){
    
    
34        System.out.println(id);
35        System.out.println(student);
36        System.out.println("修改学生");
37        return "xiaokeai";
38    }
39}

@PostMapping、@GetMapping、@PutMapping、@DeleteMapping

作用:简化设置请求方式的@RequestMapping写法

位置:方法上方。

1@Controller
2@RequestMapping("/student")
3public class StudentController {
    
    
4    // 删除学生
5    @DeleteMapping("/{id}")
6    public String deleteStudent(@PathVariable("id") int id){
    
    
7        System.out.println("删除id为"+id+"的学生");
8        return "xiaokeai";
9    }
10
11    // 根据id查询学生
12    @GetMapping("/{id}")
13    public String findStudentById(@PathVariable int id){
    
    
14        System.out.println(id);
15        System.out.println("根据id查询学生");
16        return "xiaokeai";
17    }
18
19    // 新增学生
20    @PostMapping("/{id}")
21    public String addStudent(@PathVariable int id, Student student){
    
    
22        System.out.println(id);
23        System.out.println(student);
24        System.out.println("新增学生");
25        return "xiaokeai";
26    }
27
28    // 修改学生
29    @PutMapping("/{id}")
30    public String updateStudent(@PathVariable int id, Student student){
    
    
31        System.out.println(id);
32        System.out.println(student);
33        System.out.println("修改学生");
34        return "xiaokeai";
35    }
36}

@HiddentHttpMethodFilter

由于浏览器form表单只支持GET与POST请求,而DELETE、PUT请求并不支持,SpringMVC有一个过滤器,可以将浏览器的POST请求改为指定的请求方式,发送给的控制器方法。

用法如下:

1.在web.xml中配置过滤器

1<!-- 请求方式过滤器 -->
2<filter>
3    <filter-name>httpMethodFilter</filter-name>
4    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
5</filter>
6<filter-mapping>
7    <filter-name>httpMethodFilter</filter-name>
8    <url-pattern>/*</url-pattern>
9</filter-mapping>

2.编写控制器方法

1@Controller
2@RequestMapping("/c7")
3public class MyController7 {
    
    
4    @DeleteMapping("/delete")
5    public String testDelete(){
    
    
6        System.out.println("删除方法");
7        return "xiaokeai";
8    }
9
10    @PutMapping("/put")
11    public String testPut(){
    
    
12        System.out.println("修改方法");
13        return "xiaokeai";
14    }
15}

3.在jsp中编写表单

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<html>
3    <head>
4        <title>DELETE、PUT提交</title>
5    </head>
6    <body>
7        <!-- 删除 -->
8        <%-- 提交DELETE、PUT请求,表单必须提交方式为post --%>
9        <%-- 表单中有一个隐藏域,name值为_method,value值为提交方式 --%>
10        <form action="/c7/delete" method="post">
11            <input type="hidden" name="_method" value="DELETE">
12            <input type="submit" value="删除">
13        </form>
14        <hr/>
15        <!-- 修改 -->
16        <form action="/c7/put" method="post">
17            <input type="hidden" name="_method" value="PUT">
18            <input type="submit" value="修改">
19        </form>
20    </body>
21</html>

9.@ResponseBody

作用:方法返回的对象转换为JSON格式,并将JSON数据直接写入到输出流中,使用此注解后不会再经过视图解析器。使用该注解可以处理Ajax请求。

位置:方法上方或方法返回值前

1.编写jsp页面,发送ajax请求

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<html>
3    <head>
4        <title>ajax请求</title>
5        <script src="/js/jquery-2.1.1.min.js"></script>
6        <script>
7            $(function () {
    
    
8                $("#btn").click(function () {
    
    
9                    var name = $("#name").val();
10                    var sex = $("#sex").val();
11                    $.get("/c8/addStudent",{
    
    "name":name,"sex":sex},function (data){
    
    
12                        console.log(data);
13                    });
14                });
15            });
16        </script>
17    </head>
18    <body>
19        姓名:<input id="name"/><br/>
20        性别:<input id="sex"/><br/>
21        <input type="button" value="提交" id="btn"/>
22    </body>
23</html>

2.由于jsp页面中引入jQuery的js文件,而SpringMVC会拦截所有资源,造成jquery.js失效,需要在SpringMVC核心配置文件中放行静态资源。

1<!-- 放行静态资源 -->
2<mvc:default-servlet-handler />

3.编写结果实体类,该实体类会封装一个请求的结果

1// 请求的结果对象
2public class Result {
    
       
3    private boolean flag; // 请求是否成功    
4    private String message; // 请求提示信息   
5    // 省略getter/setter/构造方法
6}

4.编写控制器

1@PostMapping("/addStudent")
2@ResponseBody
3public Result addStudent(String name, String sex) {
    
    
4    // 输出接受到的参数,模拟添加学生
5    System.out.println(name+":"+sex);
6    // 返回添加结果
7    Result result = new Result(true, "添加学生成功!");
8    return result;
9}

5.SpringMVC会将Result对象转为JSON格式写入输出流,而SpringMVC默认使用的JSON转换器是jackson,需要在pom中添加jackson依赖。

1<!-- jackson -->
2<dependency>
3    <groupId>com.fasterxml.jackson.core</groupId>
4    <artifactId>jackson-core</artifactId>
5    <version>2.9.0</version>
6</dependency>
7<dependency>
8    <groupId>com.fasterxml.jackson.core</groupId>
9    <artifactId>jackson-databind</artifactId>
10    <version>2.9.0</version>
11</dependency>
12<dependency>
13    <groupId>com.fasterxml.jackson.core</groupId>
14    <artifactId>jackson-annotations</artifactId>
15    <version>2.9.0</version>
16</dependency>

10.@RestController

如果一个控制器类下的所有控制器方法都返回JSON格式数据且不进行跳转,可以使用@RestController代替@Controller,此时每个方法上的@ResponseBody都可以省略。

1@RestController
2@RequestMapping("/c8")
3public class MyController8 {
    
        
4    @PostMapping("/addStudent")    
5    public Result addStudent(String name, String sex) {
    
     
6        // 输出接受到的参数,模拟添加学生      
7        System.out.println(name+":"+sex);       
8        // 返回结果        
9        Result result = new Result(true, "添加学生成功!"); 
10        return result;    
11    }
12}

11.静态资源映射

当在DispatcherServlet的<url-pattern>中配置拦截 “/” 时,除了jsp文件不会拦截以外,其他所有的请求都会经过前端控制器进行匹配。此时静态资源例如css、js、jpg等就会被前端控制器拦截,导致不能访问,出现404问题。想要正常映射静态资源共有三种方案:

配置静态资源筛查器

在SpringMVC的配置文件中配置<mvc:default-servlet-handler />后,会在Spring容器中创建一个资源检查器,它对进入DispatcherServlet的URL进行筛查,如果不是静态资源,才由DispatcherServlet处理。

修改SpringMVC核心配置文件:

1<mvc:default-servlet-handler/>

配置静态资源映射器

SpringMVC模块提供了静态资源映射器组件,通过<mvc:resources>标签配置静态资源映射器,配置后的路径不会由DispatcherServlet处理。

修改SpringMVC核心配置文件:

1<!--配置静态资源映射器-->
2<!-- mapping:配置请求的URL location:资源路径-->
3<mvc:resources mapping="/img/" location="/img/"/><mvc:resources mapping="/js/" location="/js/"/>

配置默认Servlet处理静态资源

web.xml可以配置默认Servlet处理静态资源,该Servlet由tomcat提供,它会直接访问静态资源不进行其他操作。这样就避免了使用DispatcherServlet对静态资源的拦截:

修改web.xml:

1<servlet-mapping>    
2    <servlet-name>default</servlet-name>   
3    <url-pattern>*.jpg</url-pattern>
4</servlet-mapping>
5<servlet-mapping>    
6    <servlet-name>default</servlet-name>  
7    <url-pattern>*.css</url-pattern>
8</servlet-mapping>
9<servlet-mapping>    
10    <servlet-name>default</servlet-name>    
11    <url-pattern>*.js</url-pattern>
12</servlet-mapping>
13<servlet-mapping>    
14    <servlet-name>default</servlet-name>   
15    <url-pattern>*.png</url-pattern>
16</servlet-mapping>

12.@RequestBody

作用:将请求中JSON格式的参数转为JAVA对象

位置:写在方法参数前

1.AJAX请求发送JSON格式的参数

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<html>
3    <head>
4        <title>ajax请求</title>
5        <script src="/js/jquery-2.1.1.min.js"></script>
6        <script>
7            $(function (){
    
    
8                $("#btn").click(function (){
    
    
9                    var name=$("#name").val();
10                    var sex=$("#sex").val();
11                    var param = JSON.stringify({
    
    "name":name,"sex":sex});
12                    $.ajax({
    
    
13                        url:"/c8/addStudent2",
14                        contentType:"application/json",
15                        type:"post",
16                        data:param,
17                        success:function (data){
    
    
18                            console.log(data);
19                        }
20                    })
21                })
22            })
23        </script>
24    </head>
25    <br>
26    姓名:<input id="name"><br />
27    性别:<input id="sex"><br />
28    <input type="button" value="提交" id="btn">
29    </body>
30</html>

2.编写控制器

1@PostMapping("/addStudent2")
2@ResponseBody
3public Result addStudent2(@RequestBody Student student) {
    
    
4    System.out.println(student);
5    // 返回添加结果
6    Result result = new Result(true, "添加学生成功!");
7    return result;
8}

五、SpringMVC文件上传

1.原生方式上传

在这里插入图片描述

1.创建新的SpringMVC项目,在web.xml中将项目从2.3改为3.1,即可默认开启el表达式

1<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
3         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
4         id="WebApp_ID" version="3.1">

2.编写上传表单

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<html>
3    <head>
4        <title>上传</title>
5    </head>
6    <body>
7        <h3>文件上传</h3>
8        <%-- 上传表单的提交方式必须是post --%>
9        <%-- enctype属性为multipart/form-data,意思是不对表单数据进行编码 --%>
10        <form action="/fileUpload" method="post" enctype="multipart/form-data">
11            <%-- 文件选择控件,类型是file,必须要有name属性--%>
12            选择文件:<input type="file" name="upload"/>
13            <input type="submit" value="上传"/>
14        </form>
15    </body>
16</html>

3.接收请求体数据:

1@RequestMapping("/fileUpload")
2public String upload(HttpServletRequest request) throws Exception {
    
    
3    // 获取输入流
4    ServletInputStream is = request.getInputStream();
5    // 从输入流获取请求体数据
6    int i = 0;
7    while ((i=is.read())!=-1){
    
    
8        System.out.println((char)i);
9    }
10    return "index";
11}

接下来需要分析请求体中的文件项,并将数据写入磁盘,此时需要借助文件上传工具

1.引入文件上传依赖:

1<!-- 文件上传 -->
2<dependency>
3    <groupId>commons-fileupload</groupId>
4    <artifactId>commons-fileupload</artifactId>
5    <version>1.3.1</version>
6</dependency>
7<dependency>
8    <groupId>commons-io</groupId>
9    <artifactId>commons-io</artifactId>
10    <version>2.4</version>
11</dependency>

2.编写控制器接收上传请求,控制器进行三步操作:

(1)创建文件夹,存放上传文件。

(2)分析请求体,找到上传文件数据。

(3)将文件数据写入文件夹。

1@RequestMapping("/fileUpload")
2public String upload(HttpServletRequest request) throws Exception {
    
    
3    // 创建文件夹,存放上传文件
4    // 1.设置上传文件夹的真实路径
5    String realPath = request.getSession().getServletContext().getRealPath("/upload");
6
7    // 2.判断该目录是否存在,如果不存在,创建该目录
8    File file = new File(realPath);
9    if(!file.exists()){
    
    
10        file.mkdirs();
11    }
12
13    // 分析请求体,找到上传文件数据
14    // 1.创建磁盘文件工厂
15    DiskFileItemFactory factory = new DiskFileItemFactory();
16    // 2.创建上传数据分析器对象
17    ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
18    // 3.利用分析器对象解析请求体,返回所有数据项
19    List<FileItem> fileItems = servletFileUpload.parseRequest(request);
20    // 4.遍历所有数据,找到文件项(非表单项)
21    for (FileItem fileItem:fileItems){
    
    
22        if(!fileItem.isFormField()){
    
    
23            // 将文件数据写入文件夹
24            // 1.获取文件名
25            String name = fileItem.getName();
26            // 2.将文件写入磁盘
27            fileItem.write(new File(file,name));
28            // 3.删除内存中的临时文件
29            fileItem.delete();
30        }
31    }
32    return "index";
33}

2.SpringMVC方式上传

SpringMVC使用框架提供的文件解析器对象,可以直接将请求体中的文件数据转为MultipartFile对象,从而省略原生上传中分析请求体的步骤。

1.在SpringMVC核心配置文件配置文件解析器

1<!-- 文件解析器对象,id名称必须是multipartResolver -->
2<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
3    <!-- 支持一次上传文件的总容量。单位:字节 100M = 100*1024*1024-->
4    <property name="maxUploadSize" value="104857600"/>
5    <!-- 文件名的编码方式-->
6    <property name="defaultEncoding" value="utf-8"/>
7</bean>

2.创建JSP表单

1<form action="/fileUpload2" method="post" enctype="multipart/form-data">
2    <input type="file" name="file"/>
3    <input type="submit" value="上传"/>
4</form>

3.编写控制器接收上传请求

1// MultipartFile参数名必须和JSP文件空间的name属性一致
2@RequestMapping("/fileUpload2")
3public String upload2(MultipartFile file,HttpServletRequest request) throws IOException {
    
    
4    // 创建文件夹,存放上传文件
5    String realPath = request.getSession().getServletContext().getRealPath("/upload");
6    File dir = new File(realPath);
7    if(!dir.exists()){
    
    
8        dir.mkdirs();
9    }
10
11    // 将上传的数据写到文件夹的文件中
12    // 1.拿到上传的文件名
13    String filename = file.getOriginalFilename();
14    filename = UUID.randomUUID()+"_"+filename;
15    // 2.创建空文件
16    File newFile = new File(dir,filename);
17    // 3.将数据写入空文件中
18    file.transferTo(newFile);
19
20    return "index";
21}

3.上传多文件

SpringMVC支持一次性上传多个文件,写法如下:

1.创建JSP表单

1<form action="/fileUpload3" method="post" enctype="multipart/form-data">
2    用户名:<input name="username"/>
3    文件1<input type="file" name="files"/>
4    文件2<input type="file" name="files"/>
5    <input type="submit" value="上传"/>
6</form>

2.编写控制器接收上传请求

1// 处理多文件上传,参数类型为MultipartFile数组,参数名和JSP文件控件的name属性一致
2@RequestMapping("/fileUpload3")
3public String upload3(MultipartFile files[],String username,HttpServletRequest request) throws Exception {
    
    
4    System.out.println(username);
5    //1.设置上传文件保存的文件夹
6    String realPath = request.getSession().getServletContext().getRealPath("/upload");
7    File dir = new File(realPath);
8    if (!dir.exists()){
    
    
9        dir.mkdirs();
10    }
11    //2.遍历数组,将上传文件保存到文件夹
12    for(MultipartFile file:files){
    
    
13        String filename = file.getOriginalFilename();
14        filename = UUID.randomUUID()+"_"+filename;
15        File newFile = new File(dir, filename);
16        file.transferTo(newFile);
17    }
18    return "index";
19}

4.异步上传

在这里插入图片描述
之前的上传方案,在上传成功后都会跳转页面。而在实际开发中,很多情况下上传后不进行跳转,而是进行页面的局部刷新,比如:上传头像成功后将头像显示在网页中。这时候就需要使用异步文件上传。

1.编写JSP页面,引入jQuery和jQuery表单上传工具jquery.form.js

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<html>
3<head>
4    <title>上传</title>
5    <script src="/js/jquery-2.1.1.min.js"></script>
6    <script src="/js/jquery.form.js"></script>
7</head>
8<body>
9<h3>文件上传</h3>
10<form id="ajaxForm" enctype="multipart/form-data" >
11    <input type="file" name="file"/>
12    <%-- 按钮类型不能是submit,否则会刷新页面   --%>
13    <input type="button" value="上传头像" id="btn"/>
14</form>
15<%-- 上传头像后展示的位置 --%>
16<img src="/" width="100" id="img">
17<script>
18    $(function () {
    
    
19        $("#btn").click(function () {
    
    
20            // 异步提交表单
21            $("#ajaxForm").ajaxSubmit({
    
    
22                url:"/fileUpload4",
23                type:"post",
24                success:function (data) {
    
    
25                    $("#img").attr("src",data);
26                }
27            })
28        })
29    })
30</script>
31</body>
32</html>

2.编写控制器接收异步上传请求

1@RequestMapping("/fileUpload4")
2//不进行页面跳转
3@ResponseBody
4public String upload3(HttpServletRequest request, MultipartFile file) throws Exception {
    
    
5    // 创建文件夹,存放上传文件。
6    String realPath = request.getSession().getServletContext().getRealPath("/upload");
7    File dir = new File(realPath);
8    if (!dir.exists()){
    
    
9        dir.mkdirs();
10    }
11
12    // 拿到上传文件名
13    String filename = file.getOriginalFilename();
14    filename = UUID.randomUUID()+"_"+filename;
15    // 创建空文件
16    File newFile = new File(dir, filename);
17    // 将上传的文件写到空文件中
18    file.transferTo(newFile);
19    // 返回文件的路径
20    return "/upload/"+filename;
21}

5.跨服务器上传

在这里插入图片描述
由于文件占据磁盘空间较大,在实际开发中往往会将文件上传到其他服务器中,此时需要使用跨服务器上传文件。

1.tomcat作为图片服务器,在tomcat的webapps下创建upload目录作为文件上传目录。

2.修改tomcat的conf/web.xml文件,支持跨服上传。

1<servlet>    
2    <init-param>        
3        <param-name>readonly</param-name>     
4        <param-value>false</param-value>    
5    </init-param>
6</servlet>

3.修改tomcat的conf/server.xml文件,修改tomcat端口,修改完开启tomcat服务器

4.编写JSP上传表单

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<html>
3    <head>
4        <title>上传</title>
5        <script src="/js/jquery-2.1.1.min.js"></script>
6        <script src="/js/jquery.form.js"></script>
7    </head>
8    <body>
9        <h3>文件上传</h3>
10        <form id="ajaxForm" enctype="multipart/form-data" >
11            <input type="file" name="file"/>
12            <input type="button" value="上传头像" id="btn"/>
13        </form>
14        <img src="/" width="100" id="img">
15        <script>
16            $(function () {
    
    
17                $("#btn").click(function () {
    
    
18                    $("#ajaxForm").ajaxSubmit({
    
    
19                        url:"/fileUpload5",
20                        type:"post",
21                        success:function (data) {
    
    
22                            $("#img").attr("src",data);
23                        }
24                    })
25                })
26            })
27        </script>
28    </body>
29</html>

5.添加跨服上传依赖

1<!-- 跨服上传 -->
2<dependency>
3    <groupId>com.sun.jersey</groupId>
4    <artifactId>jersey-core</artifactId>
5    <version>1.18.1</version>
6</dependency>
7<dependency>
8    <groupId>com.sun.jersey</groupId>
9    <artifactId>jersey-client</artifactId>
10    <version>1.18.1</version>
11</dependency>

6.创建控制器方法,该方法在接受到上传请求后将文件保存到其他服务器上。

1@RequestMapping("/fileUpload5")
2@ResponseBody
3public String upload4(HttpServletRequest request, MultipartFile file) throws Exception {
    
    
4    // 设置跨服上传的服务器路径
5    String path = "http://localhost:"端口号"/upload/";
6    // 获取上传的文件名
7    String filename = file.getOriginalFilename();
8    filename = UUID.randomUUID()+"_"+filename;
9
10    // 跨服上传:
11    // 1.创建客户端对象
12    Client client = Client.create();
13    // 2.使用客户端对象连接图片服务器
14    WebResource resource = client.resource(path + filename);
15    //3.传输数据
16    resource.put(file.getBytes());
17
18    return path+filename;
19}

6.文件下载

将文件上传到服务器后,有时我们需要让用户下载上传的文件,接下来我们编写文件下载功能:

查询所有可下载的文件

1.编写控制器方法,查询所有可下载的文件,并跳转到下载页面

1// 查询可下载的文件
2@RequestMapping("/showFiles")
3public String showFileDown(HttpServletRequest request, Model model){
    
    
4    //1.获取下载文件路径集合。注:跨服务器上传中,网络路径无法获取文件列表。
5    String path = request.getSession().getServletContext().getRealPath("/upload");
6    File file = new File(path);
7    String[] files = file.list();
8    //2.将路径放入模型中,跳转到JSP页面
9    model.addAttribute("files",files);
10    return "download";
11}

2.添加JSTL依赖

1<!-- JSTL -->
2<dependency>
3    <groupId>org.apache.taglibs</groupId>
4    <artifactId>taglibs-standard-spec</artifactId>
5    <version>1.2.5</version>
6</dependency>
7<dependency>
8    <groupId>org.apache.taglibs</groupId>
9    <artifactId>taglibs-standard-impl</artifactId>
10    <version>1.2.5</version>
11</dependency>

3.编写下载页面

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
3<html>
4    <head>
5        <title>下载</title>
6    </head>
7    <body>
8        <h3>文件下载</h3>
9        <%-- 遍历文件集合 --%>
10        <c:forEach items="${files}" var="file">
11            <a href="/download?fileName=${file}">${
    
    file}</a><br/>
12        </c:forEach>
13    </body>
14</html>

编写下载控制器

1// 文件下载
2@RequestMapping("/download")
3public void fileDown(HttpServletRequest request, HttpServletResponse response,String fileName) throws IOException {
    
    
4    // 设置响应头
5    response.setHeader("Content-Disposition","attachment;filename="+fileName);
6    // 获取文件路径
7    String path = request.getSession().getServletContext().getRealPath("/upload");
8    File file = new File(path,fileName);
9    // 获取字节输出流
10    ServletOutputStream os = response.getOutputStream();
11    // 使用输出流写出文件
12    os.write(FileUtils.readFileToByteArray(file));
13    os.flush();
14    os.close();
15}

六、SpringMVC异常处理

1.单个控制器异常处理

在系统当中, Dao、Service、Controller层代码出现都可能抛出异常。如果哪里产生异常就在哪里处理,则会降低开发效率。所以一般情况下我们会让异常向上抛出,最终到达DispatcherServlet中,此时SpringMVC提供了异常处理器进行异常处理,这样可以提高开发效率。

在这里插入图片描述

处理单个Controller的异常:

1@Controller
2public class MyController {
    
    
3    @RequestMapping("/t1")
4    public String t1(){
    
    
5        String str = null;
6        //        str.length();
7        //        int flag = 1/0;
8        int[] arr = new int[1];
9        arr[2] = 10;
10        return "index";
11    }
12
13    /**
14     * 异常处理方法
15     * @param ex 异常对象
16     * @param model 模型对象
17     * @return
18     */
19    // 添加@ExceptionHandler,表示该方法是处理异常的方法,属性为处理的异常类
20    @ExceptionHandler({
    
    java.lang.NullPointerException.class,java.lang.ArithmeticException.class})
21    public String exceptionHandle1(Exception ex, Model model){
    
    
22        // 向模型中添加异常对象
23        model.addAttribute("msg",ex);
24        // 跳转到异常页面
25        return "error";
26    }
27
28    // 方法一不能处理的异常交给方法二处理
29    @ExceptionHandler(java.lang.Exception.class)
30    public String exceptionHandle2(Exception ex, Model model){
    
    
31        model.addAttribute("msg",ex);
32        return "error2";
33    }
34}

异常页面error.jsp

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<html>
3    <head>
4        <title>出错了!</title>
5    </head>
6    <body>
7        <h3>ERROR 发生异常!${
    
    msg}</h3>
8    </body>
9</html>

异常页面error2.jsp

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<html>
3    <head>
4        <title>出错了!</title>
5    </head>
6    <body>
7        <h3>ERROR2 发生严重异常!${
    
    msg}</h3>
8    </body>
9</html>

2.全局异常处理

在控制器中定义异常处理方法只能处理该控制器类的异常,要想处理所有控制器的异常,需要定义全局异常处理类。

1.编写另一个有异常的控制器类

1@Controller
2public class MyController2 {
    
    
3    @RequestMapping("/t2")
4    public String t2(){
    
    
5        int[] arr = new int[1];
6        arr[2] = 10;
7        return "index";
8    }
9}

2.编写全局异常处理器类

1// 全局异常处理器类,需要添加@ControllerAdvice
2@ControllerAdvice
3public class GlobalExceptionHandler {
    
    
4    /**
5     * 异常处理方法
6     *
7     * @param ex    异常对象
8     * @param model 模型对象
9     * @return
10     */
11    // 添加@ExceptionHandler,表示该方法是处理异常的方法,属性为处理的异常类
12    @ExceptionHandler({
    
    java.lang.NullPointerException.class, java.lang.ArithmeticException.class})
13    public String exceptionHandle1(Exception ex, Model model) {
    
    
14        // 向模型中添加异常对象
15        model.addAttribute("msg", ex);
16        // 跳转到异常页面
17        return "error";
18    }
19
20    // 方法一不能处理的异常交给方法二处理
21    @ExceptionHandler(java.lang.Exception.class)
22    public String exceptionHandle2(Exception ex, Model model) {
    
    
23        model.addAttribute("msg", ex);
24        return "error2";
25    }
26}

3.自定义异常处理器

以上方式都是使用的SpringMVC自带的异常处理器进行异常处理,我们还可以自定义异常处理器处理异常:

1// 自定义异常处理器实现HandlerExceptionResolver接口,并放入Spring容器中
2@Component
3public class MyExceptionHandler implements HandlerExceptionResolver {
    
    
4    @Override
5    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
    
    
6        ModelAndView modelAndView = new ModelAndView();
7        if (e instanceof NullPointerException) {
    
    
8            modelAndView.setViewName("error");
9        } else {
    
    
10            modelAndView.setViewName("error2");
11        }
12        modelAndView.addObject("msg", e);
13        return modelAndView;
14    }
15}

七、SpringMVC拦截器

1.拦截器简介

在这里插入图片描述
SpringMVC的拦截器(Interceptor)也是AOP思想的一种实现方式。它与Servlet的过滤器(Filter)功能类似,主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。

拦截器和过滤器的区别

拦截器是SpringMVC组件,而过滤器是Servlet组件。
拦截器不依赖Web容器,过滤器依赖Web容器。
拦截器只能对控制器请求起作用,而过滤器则可以对所有的请求起作用。
拦截器可以直接获取IOC容器中的对象,而过滤器就不太方便获取。

2.拦截器使用

接下来我们使用SpringMVC拦截器

1.使用maven创建SprinMVC的web项目

2.创建控制器方法

1@RequestMapping("/m1")
2public String m1(){
    
    
3    System.out.println("控制器方法");
4    return "result";
5}

3.创建拦截器类,该类实现HandlerInterceptor接口,需要重写三个方法:

preHandle:请求到达Controller前执行的方法,返回值为true通过拦截器,返回值为false被拦截器拦截。
postHandle:跳转到JSP前执行的方法
afterCompletion:跳转到JSP后执行的方法

1// 拦截器类
2public class MyInterceptor implements HandlerInterceptor {
    
    
3    // 请求到达Controller前执行
4    @Override
5    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    
    
6        System.out.println("请求到达Controller前");
7        // 如果return false则无法到达Controller
8        return true;
9    }
10
11    // 跳转到JSP前执行,此时可以向Request域添加数据
12    @Override
13    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    
    
14        System.out.println("跳转到JSP前");
15        request.setAttribute("name","百战");
16    }
17
18    // 跳转到JSP后执行,此时已经不能向Request域添加数据
19    @Override
20    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    
    
21        System.out.println("跳转到JSP后");
22        request.setAttribute("age",10);
23    }
24}

4.编写JSP页面

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<html>
3    <head>
4        <title>结果</title>
5    </head>
6    <body>
7        <h3>name:${
    
    requestScope.name}</h3>
8        <h3>age:${
    
    requestScope.age}</h3>
9    </body>
10</html>

5.在SpringMVC核心配置文件中配置拦截器

1<!-- 配置拦截器-->
2<mvc:interceptors>   
3    <mvc:interceptor>        
4        <!-- 配置拦截器的作用路径-->       
5        <mvc:mapping path="/**"/>        
6        <!-- 拦截器对象 -->       
7        <bean class="com.package.interceptor.MyInterceptor"/>  
8    </mvc:interceptor>
9</mvc:interceptors>

3.全局拦截器

全局拦截器可以拦截所有控制器处理的URL,作用等于/**,配置方式如下:

1<!-- 配置拦截器 -->
2<mvc:interceptors>   
3    <!-- 全局拦截器 -->    
4    <bean class="com.package.interceptor.MyInterceptor">
5    </bean>
6</mvc:interceptors>

4.拦截器链与执行顺序

在这里插入图片描述
如果一个URL能够被多个拦截器所拦截,全局拦截器最先执行,其他拦截器根据配置文件中配置的从上到下执行,接下来我们再配置一个拦截器:

1.编写拦截器类

1public class MyInterceptor2 implements HandlerInterceptor {
    
    
2    @Override
3    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    
    
4        System.out.println("拦截器2:请求到达Controller前");
5        return true;
6    }
7
8    @Override
9    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    
    
10        System.out.println("拦截器2:跳转到JSP前");
11    }
12
13    @Override
14    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    
    
15        System.out.println("拦截器2:跳转到JSP后");
16    }
17}

2.配置拦截器链

1<!-- 配置拦截器 -->
2<mvc:interceptors>
3    <!-- 拦截器1 -->
4    <mvc:interceptor>
5        <mvc:mapping path="/**"/>
6        <bean class="com.package.interceptor.MyInterceptor"/>
7    </mvc:interceptor>
8    <!-- 拦截器2 -->
9    <mvc:interceptor>
10        <mvc:mapping path="/**"/>
11        <bean class="com.package.interceptor.MyInterceptor2"/>
12    </mvc:interceptor>
13</mvc:interceptors>

访问控制器方法后输出如下:

在这里插入图片描述

结论:

1.preHandle()顺序执行,postHandle()、afterComletion()逆序执行。
2.只要有一个preHandle()拦截,后面的preHandle(),postHandle()都不会执行。
3.只要相应的preHandle()放行,afterComletion()就会执行。

5.拦截器过滤敏感词案例

在这里插入图片描述
接下来我们编写一个拦截器案例,需求如下:

在系统中,我们需要将所有响应中的一些敏感词替换为***,此时可以使用拦截器达到要求:

1.编写控制器方法

1@RequestMapping("/m2")
2public String m2(Model model){
    
    
3    model.addAttribute("name","大敏感词1");
4    return "result";
5}

2.编写敏感词拦截器

1// 敏感词拦截器
2public class SensitiveWordInterceptor implements HandlerInterceptor {
    
    
3    @Override
4    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    
    
5        return true;
6    }
7
8    @Override
9    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    
    
10        // 敏感词列表
11        String[] sensitiveWords = {
    
    "敏感词1","敏感词2","敏感词3"};
12        // 获取model中所有数据
13        Map<String, Object> model = modelAndView.getModel();
14        Set<Map.Entry<String, Object>> entries = model.entrySet();
15
16        // 遍历model
17        for (Map.Entry<String, Object> entry : entries) {
    
    
18            String key = entry.getKey();
19            String value = entry.getValue().toString();
20            // 将model值和敏感词列表遍历比对
21            for (String sensitiveWord : sensitiveWords) {
    
    
22                // 如果model值包含敏感词,则替换
23                if(value.contains(sensitiveWord)){
    
    
24                    String newStr = value.replaceAll(sensitiveWord, "***");
25                    model.put(key, newStr);
26                }
27            }
28        }
29    }
30}

3.配置拦截器

1<!-- 配置拦截器-->
2<mvc:interceptors>
3    <!-- 敏感词拦截器 -->
4    <mvc:interceptor>
5        <mvc:mapping path="/**"/>
6        <bean class="com.package.interceptor.SensitiveWordInterceptor"></bean>
7    </mvc:interceptor>
8</mvc:interceptors>

八、SpringMVC跨域请求

1.同源策略

同源策略是浏览器的一个安全功能。同源,指的是两个URL的协议,域名,端口相同。浏览器出于安全方面的考虑,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。

哪些不受同源策略限制:

1.页面中的<a>跳转、表单提交不会受到同源策略限制的。
2.静态资源引入也不会受到同源策略限制。如嵌入到页面中的<script src=""><img src=""><link href="">等。
最容易收到同源策略影响的就是Ajax请求。

2.跨域请求

当请求URL的协议、域名、端口三者中任意一个与当前页面URL不同时即为跨域。浏览器执行JavaScript脚本时,会检查当前请求是否同源,如果不是同源资源,就不会被执行。
比如:

1.编写控制器方法

1@RequestMapping("/m3")
2@ResponseBody
3public String m3(){
    
    
4    System.out.println("测试跨域请求");
5    return "success";
6}

2.编写JSP页面,发送异步请求

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<html>
3    <head>
4        <title>跨域请求</title>
5        <script src="/js/jquery-2.1.1.min.js"></script>
6        <script>
7            $(function (){
    
    
8                $("#btn").click(function () {
    
    
9                    // $.get("http://localhost:8080/m3",function (data) {
    
    
10                    //     console.log(data);
11                    // })
12                    $.get("http://127.0.0.1:8080/m3",function (data) {
    
    
13                        console.log(data);
14                    })
15                })
16            })
17        </script>
18    </head>
19    <body>
20        <button id="btn">异步请求</button>
21    </body>
22</html>

结果:

当浏览器通过http://localhost:8080/cross.jsp访问JSP页面时

http://localhost:8080/m3 能发送异步请求;
http://127.0.0.1:8080/m3 由于同源无法发送异步请求,报以下异常:
在这里插入图片描述

3.控制器接收跨域请求

SpringMVC提供了注解@CrossOrigin解决跨域问题。用法如下:

1@RequestMapping("/m3")
2@ResponseBody
3// 如果请求从http://localhost:8080发出,则允许跨域访问
4@CrossOrigin("http://localhost:8080")
5public String m3(){
    
    
6    System.out.println("测试跨域请求");
7    return "success";
8}

九、SSM整合

1.需求分析

接下来我们使用Maven+Spring+MyBatis+SpringMVC完成一个案例,案例需求为在页面可以进行添加学生+查询所有学生!

案例需要使用以下技术:

使用Maven创建聚合工程,并使用Maven的tomcat插件运行工程
使用Spring的IOC容器管理对象
使用MyBatis操作数据库
使用Spring的声明式事务进行事务管理
使用SpringMVC作为控制器封装Model并跳转到JSP页面展示数据
使用Junit测试方法
使用Log4j在控制台打印日志

案例的编写流程如下:

1.创建maven父工程,添加需要的依赖和插件
2.创建dao子工程,配置MyBatis操作数据库,配置Log4j在控制台打印日志。
3.创建service子工程,配置Spring声明式事务
4.创建controller子工程,配置SpringMVC作为控制器,编写JSP页面展示数据。
5.每个子工程都使用Spring进行IOC管理

1# 准备数据库数据
2CREATE DATABASE `student`;
3USE `student`;
4DROP TABLE IF EXISTS `student`;
5CREATE TABLE `student` (
6  `id` INT(11) NOT NULL AUTO_INCREMENT,
7  `name` VARCHAR(255) DEFAULT NULL,
8  `sex` VARCHAR(10) DEFAULT NULL,
9  `address` VARCHAR(255) DEFAULT NULL,
10  PRIMARY KEY (`id`)
11) ENGINE=INNODB CHARSET=utf8;
12INSERT  INTO `student`(`id`,`name`,`sex`,`address`) VALUES (1,'hututu','男','翻斗花园'),(2,'小可爱','女','北京');

2.创建父工程

创建maven父工程,添加需要的依赖和插件

1<properties>
2    <!--Spring版本-->
3    <spring.version>5.2.12.RELEASE</spring.version>
4</properties>
5
6<dependencies>
7    <!-- mybatis -->
8    <dependency>
9        <groupId>org.mybatis</groupId>
10        <artifactId>mybatis</artifactId>
11        <version>3.5.7</version>
12    </dependency>
13    <!-- mysql驱动 -->
14    <dependency>
15        <groupId>mysql</groupId>
16        <artifactId>mysql-connector-java</artifactId>
17        <version>8.0.26</version>
18    </dependency>
19    <!--  druid连接池  -->
20    <dependency>
21        <groupId>com.alibaba</groupId>
22        <artifactId>druid</artifactId>
23        <version>1.2.8</version>
24    </dependency>
25    <!-- MyBatis与Spring的整合包-->
26    <dependency>
27        <groupId>org.mybatis</groupId>
28        <artifactId>mybatis-spring</artifactId>
29        <version>2.0.6</version>
30    </dependency>
31    <dependency>
32        <groupId>org.springframework</groupId>
33        <artifactId>spring-jdbc</artifactId>
34        <version>${spring.version}</version>
35    </dependency>
36    <!-- springmvc -->
37    <dependency>
38        <groupId>org.springframework</groupId>
39        <artifactId>spring-context</artifactId>
40        <version>${spring.version}</version>
41    </dependency>
42    <dependency>
43        <groupId>org.springframework</groupId>
44        <artifactId>spring-web</artifactId>
45        <version>${spring.version}</version>
46    </dependency>
47    <dependency>
48        <groupId>org.springframework</groupId>
49        <artifactId>spring-webmvc</artifactId>
50        <version>${spring.version}</version>
51    </dependency>
52    <!-- 事务 -->
53    <dependency>
54        <groupId>org.springframework</groupId>
55        <artifactId>spring-tx</artifactId>
56        <version>${spring.version}</version>
57    </dependency>
58    <dependency>
59        <groupId>org.aspectj</groupId>
60        <artifactId>aspectjweaver</artifactId>
61        <version>1.8.7</version>
62    </dependency>
63    <!-- jstl -->
64    <dependency>
65        <groupId>org.apache.taglibs</groupId>
66        <artifactId>taglibs-standard-spec</artifactId>
67        <version>1.2.5</version>
68    </dependency>
69    <dependency>
70        <groupId>org.apache.taglibs</groupId>
71        <artifactId>taglibs-standard-impl</artifactId>
72        <version>1.2.5</version>
73    </dependency>
74    <!-- servlet -->
75    <dependency>
76        <groupId>javax.servlet</groupId>
77        <artifactId>servlet-api</artifactId>
78        <version>2.5</version>
79        <scope>provided</scope>
80    </dependency>
81    <!-- jsp -->
82    <dependency>
83        <groupId>javax.servlet.jsp</groupId>
84        <artifactId>jsp-api</artifactId>
85        <version>2.0</version>
86        <scope>provided</scope>
87    </dependency>
88    <!-- junit -->
89    <dependency>
90        <groupId>junit</groupId>
91        <artifactId>junit</artifactId>
92        <version>4.12</version>
93        <scope>test</scope>
94    </dependency>
95    <dependency>
96        <groupId>org.springframework</groupId>
97        <artifactId>spring-test</artifactId>
98        <version>${spring.version}</version>
99    </dependency>
100    <!-- log4j -->
101    <dependency>
102        <groupId>log4j</groupId>
103        <artifactId>log4j</artifactId>
104        <version>1.2.12</version>
105    </dependency>
106</dependencies>
107
108<build>
109    <plugins>
110        <!-- tomcat插件 -->
111        <plugin>
112            <groupId>org.apache.tomcat.maven</groupId>
113            <artifactId>tomcat7-maven-plugin</artifactId>
114            <version>2.1</version>
115            <configuration>
116                <port>8080</port>
117                <path>/</path>
118                <uriEncoding>UTF-8</uriEncoding>
119                <server>tomcat7</server>
120                <systemProperties>
121                    <java.util.logging.SimpleFormatter.format>%1$tH:%1$tM:%1$tS %2$s%n%4$s: %5$s%6$s%n
122                    </java.util.logging.SimpleFormatter.format>
123                </systemProperties>
124            </configuration>
125        </plugin>
126    </plugins>
127</build>

3.创建dao子工程

1.在父工程下创建maven普通java子工程

2.编写实体类

1public class Student {
2    private int id;
3    private String name;
4    private String sex;
5    private String address;
6    // 省略getter/setter/tostring/构造方法
7}

3.编写持久层接口

1@Repository
2public interface StudentDao {
3    // 查询所有学生
4    @Select("select * from student")
5    List<Student> findAll();
6    
7    // 添加学生
8    @Insert("insert into student values(null,#{name},#{sex},#{address})")
9    void add(Student student);
10}

4.编写log4j.properties配置文件

1log4j.rootCategory=debug, CONSOLE, LOGFILE
2
3log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
4
5log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
6log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
7log4j.appender.CONSOLE.layout.ConversionPattern=[%d{MM/dd HH:mm:ss}] %-6r [%15.15t] %-5p %30.30c %x - %m\n

5.编写数据库配置文件druid.properties

1jdbc.driverClassName=com.mysql.jdbc.Driver
2jdbc.url=jdbc:mysql:///student
3jdbc.username=username
4jdbc.password=password

6.编写MyBatis配置文件SqlMapConfig.xml

1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE configuration
3        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
4        "http://mybatis.org/dtd/mybatis-3-config.dtd">
5<configuration>
6</configuration>

7.编写Spring配置文件applicationContext-dao.xml

1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4       xmlns:context="http://www.springframework.org/schema/context"
5       xsi:schemaLocation="http://www.springframework.org/schema/beans
6                           http://www.springframework.org/schema/beans/spring-beans.xsd
7                           http://www.springframework.org/schema/context
8                           http://www.springframework.org/schema/context/spring-context.xsd">
9    <!-- 读取数据库配置文件  -->
10    <context:property-placeholder location="classpath:druid.properties"></context:property-placeholder>
11
12    <!--  配置数据源  -->
13    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
14        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
15        <property name="url" value="${jdbc.url}"></property>
16        <property name="username" value="${jdbc.username}"></property>
17        <property name="password" value="${jdbc.password}"></property>
18    </bean>
19
20    <!--  SqlSessionFactory  -->
21    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
22        <property name="dataSource" ref="dataSource"></property>
23        <property name="configLocation" value="classpath:SqlMapConfig.xml"></property>
24    </bean>
25
26    <!-- 配置扫描包对象,为包下的接口创建代理对象  -->
27    <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
28        <property name="basePackage" value="com.package.dao"></property>
29    </bean>
30</beans>

8.测试持久层接口的方法

1@RunWith(SpringJUnit4ClassRunner.class)
2@ContextConfiguration(locations = "classpath:applicationContext-dao.xml")
3public class StudentDaoTest {
4    @Autowired
5    private StudentDao studentDao;
6    @Test
7    public void testFindAll(){
8        List<Student> all = studentDao.findAll();
9        all.forEach(System.out::println);
10    }
11
12    @Test
13    public void testAdd(){
14        Student student = new Student(0, "JK", "女", "上海");
15        studentDao.add(student);
16    }
17}

4.创建service子工程

1.在父工程下创建maven普通java子工程

2.service子工程引入dao子工程的依赖

1<dependencies>
2    <dependency>
3        <groupId>com.itbaizhan</groupId>
4        <artifactId>ssm_dao</artifactId>
5        <version>1.0-SNAPSHOT</version>
6    </dependency>
7</dependencies>

3.创建服务层方法

1@Service
2public class StudentService {
3    @Autowired
4    private StudentDao studentDao;
5    public List<Student> findAllStudent(){
6        return studentDao.findAll();
7    }
8    
9    public void addStudent(Student student){
10        studentDao.add(student);
11    }
12}

4.创建服务层的Spring配置文件applicationContext-service.xml,配置声明式事务

1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4       xmlns:context="http://www.springframework.org/schema/context"
5       xmlns:aop="http://www.springframework.org/schema/aop"
6       xmlns:tx="http://www.springframework.org/schema/tx"
7       xsi:schemaLocation="http://www.springframework.org/schema/beans
8        http://www.springframework.org/schema/beans/spring-beans.xsd
9        http://www.springframework.org/schema/context
10        http://www.springframework.org/schema/context/spring-context.xsd
11        http://www.springframework.org/schema/aop
12        http://www.springframework.org/schema/aop/spring-aop.xsd
13        http://www.springframework.org/schema/tx
14        http://www.springframework.org/schema/tx/spring-tx.xsd">
15    <!-- 包扫描 -->
16    <context:component-scan base-package="com.itbaizhan.service"></context:component-scan>
17
18    <!-- 事务管理器 -->
19    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
20        <property name="dataSource" ref="dataSource"></property>
21    </bean>
22    
23    <!-- 通知 -->
24    <tx:advice id="txAdvice" transaction-manager="transactionManager">
25        <tx:attributes>
26            <tx:method name="*"/>
27        </tx:attributes>
28    </tx:advice>
29    
30    <!-- 切面 -->
31    <aop:config>
32        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.package.service.*.*(..))"></aop:advisor>
33    </aop:config>
34</beans>

5.创建controller子工程

1.在父工程下使用maven创建web类型子工程

2.controller工程引入service子工程的依赖,并配置ssm父工程

1<parent>
2    <artifactId>ssm_demo</artifactId>
3    <groupId>com.itbaizhan</groupId>
4    <version>1.0-SNAPSHOT</version>
5</parent>
6
7<dependencies>
8    <dependency>
9        <groupId>com.itbaizhan</groupId>
10        <artifactId>ssm_service</artifactId>
11        <version>1.0-SNAPSHOT</version>
12    </dependency>
13</dependencies>

3.编写控制器类

1@Controller
2@RequestMapping("/student")
3public class StudentController {
4    @Autowired
5    private StudentService studentService;
6
7    @RequestMapping("/all")
8    public String all(Model model){
9        List<Student> allStudent = studentService.findAllStudent();
10        model.addAttribute("students",allStudent);
11        return "allStudent";
12    }
13    
14    @RequestMapping("/add")
15    public String add(Student student){
16        studentService.addStudent(student);
17        // 重定向到查询所有学生
18        return "redirect:/student/all";
19    }
20}

4.编写SpringMVC配置文件springmvc.xml

1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3       xmlns:mvc="http://www.springframework.org/schema/mvc"
4       xmlns:context="http://www.springframework.org/schema/context"
5       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6       xsi:schemaLocation="
7        http://www.springframework.org/schema/beans
8        http://www.springframework.org/schema/beans/spring-beans.xsd
9        http://www.springframework.org/schema/mvc
10        http://www.springframework.org/schema/mvc/spring-mvc.xsd
11        http://www.springframework.org/schema/context
12        http://www.springframework.org/schema/context/spring-context.xsd">
13
14    <!-- 扫描Controller包 -->
15    <context:component-scan base-package="com.package.controller"/>
16
17    <!-- 配置视图解析器 -->
18    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
19        <property name="prefix" value="/"/>
20        <property name="suffix" value=".jsp"/>
21    </bean>
22    <!-- 开启SpringMVC注解的支持 -->
23    <mvc:annotation-driven/>
24    <!-- 放行静态资源 -->
25    <mvc:default-servlet-handler />
26</beans>

5.编写Spring的总配置文件applicationContext.xml,该文件引入dao和service层的Spring配置文件

1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4       xsi:schemaLocation="http://www.springframework.org/schema/beans
5        http://www.springframework.org/schema/beans/spring-beans.xsd">
6    <import resource="applicationContext-dao.xml"></import>
7    <import resource="applicationContext-service.xml"></import>
8
9</beans>

6.在web.xml中配置Spring监听器,该监听器会监听服务器启动,并自动创建Spring的IOC容器

1<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
2         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
4         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
5         version="3.1">
6
7    <display-name>Archetype Created Web Application</display-name>
8
9    <!-- 创建spring容器的监听器 -->
10    <listener>
11        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
12    </listener>
13    <context-param>
14        <param-name>contextConfigLocation</param-name>
15        <param-value>classpath:applicationContext.xml</param-value>
16    </context-param>
17</web-app>

7.在web.xml中配置SpringMVC的前端控制器和编码过滤器

1<!--前端控制器-->
2<servlet>
3    <servlet-name>dispatcherServlet</servlet-name>
4    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
5    <init-param>
6        <param-name>contextConfigLocation</param-name>
7        <param-value>classpath:springmvc.xml</param-value>
8    </init-param>
9    <load-on-startup>1</load-on-startup>
10</servlet>
11<servlet-mapping>
12    <servlet-name>dispatcherServlet</servlet-name>
13    <url-pattern>/</url-pattern>
14</servlet-mapping>
15
16<!--编码过滤器-->
17<filter>
18    <filter-name>encFilter</filter-name>
19    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
20    <init-param>
21        <param-name>encoding</param-name>
22        <param-value>utf-8</param-value>
23    </init-param>
24</filter>
25<filter-mapping>
26    <filter-name>encFilter</filter-name>
27    <url-pattern>/*</url-pattern>
28</filter-mapping>

8.编写JSP页面allStudent.jsp

1<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
3<html>
4    <head>
5        <title>所有学生</title>
6    </head>
7    <body>
8        <%-- 添加学生表单 --%>
9        <form action="/student/add" method="post">
10            姓名:<input name="name">
11            性别:<input name="sex">
12            地址:<input name="address">
13            <input type="submit" value="提交">
14        </form>
15        <%-- 展示学生表格 --%>
16        <table width="500" cellpadding="0" cellspacing="0" border="1" align="center">
17            <tr>
18                <th>id</th>
19                <th>姓名</th>
20                <th>性别</th>
21                <th>地址</th>
22            </tr>
23            <c:forEach items="${students}" var="student">
24                <tr>
25                    <td>${student.id}</td>
26                    <td>${student.name}</td>
27                    <td>${student.sex}</td>
28                    <td>${student.address}</td>
29                </tr>
30            </c:forEach>
31        </table>
32    </body>
33</html>

6.运行项目

1.在idea中配置使用tomcat插件启动maven父项目
在这里插入图片描述
2.启动项目,访问http://localhost:8080/student/all

猜你喜欢

转载自blog.csdn.net/TIpotencial/article/details/123977171
今日推荐