Spring MVC开发实战SSM环境搭建及后端接口简单实例

得意时要看淡,失意时要看开。不论得意失意,切莫大意;不论成功失败,切莫止步。志得意满时,需要的是淡然,给自己留一条退路;失意落魄时,需要的是泰然,给自己觅一条出路Spring MVC开发实战SSM环境搭建及后端接口简单实例,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

Spring MVC环境部署

maven新建web-MVC项目,pom.xml中导入核心依赖包:

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.19.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.2.19.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.2.19.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.19.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.19.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.19.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.19.RELEASE</version>
    </dependency>

spring-mvc.xml核心文件配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

	<!--开启上下文连接注解驱动-->
    <context:annotation-config></context:annotation-config>
    <!--开启包的注解扫描-->
    <context:component-scan base-package="spring"/>
    <!--开启控制器注解驱动-->
    <mvc:annotation-driven></mvc:annotation-driven>
    <!--上面只是Spring mvc核心配置,如果用到了Spring其他功能自行配置-->

</beans>

web.xml核心文件的配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://JAVA.sun.com/xml/ns/j2ee
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<!--注释一
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.gif</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.png</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
  </servlet-mapping>
-->


  <servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<!--注释二
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
-->

    <load-on-startup>1</load-on-startup>


  </servlet>
  <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

DispatcherServlet负责管理和分发控制器,除了两个注释是最核心的配置。具体看之前的文章Spring MVC框架基础知识注释二作用是引入spring MVC的配置文件初始化配置参数。DispatcherServlet 的工作流程 :
1、向服务器发送 HTTP 请求,请求被前端控制器 DispatcherServlet 捕获。
2、 DispatcherServlet 根据 WEB-INF下的xxx-servlet.xml 中的配置对请求的 URL 进行解析,得到请求资源标识符(URI)。然后根据该 URI,调用 HandlerMapping获得该 Handler(控制器) 配置的所有相关的对象(包括 Handler 对象以及 Handler 对象对应的拦截器),最后以 HandlerExecutionChain 对象的形式返回。
3、DispatcherServlet 根据获得的 Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得 HandlerAdapter 后,此时将开始执行拦截器的 preHandler(…)方法)。
4、提取 Request 中的模型数据,填充 Handler 入参,开始执行 Handler( Controller)。在填充 Handler 的入参过程中,根据你的配置,Spring 将帮你做一些额外的工作:

  • 数据转换:对请求消息进行数据转换。如 String 转换成 Integer等。

  • HttpMessageConveter:将请求消息(如 Json、xml 等数据)转换成一个对象,将对象转换为指定的响应信息。

  • 数据格式化化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等。

  • 数据验证:验证数据的有效性(长度、格式等),验证结果存储到BindingResult 或 Error 中。

  • Handler(Controller)执行完成后,向 DispatcherServlet 返回一个ModelAndView 对象。

  • 根据返回的 ModelAndView,选择一个适合的 ViewResolver(必须是已经注册到 Spring 容器中的 ViewResolver)返回给 DispatcherServlet。

  • ViewResolver 结合 Model 和 View,来渲染视图。

  • 视图负责将渲染结果返回给客户端。

spring配置文件一般会放在Maven的resources目录下,但DispatcherServlet默认再WEB-INF目录下寻找,通过注释二的初始化配置路径。当然如果直接放在WEB-INF目录下就不需要配置了。

静态资源放行

完成上面的配置后启动服务器,上下文连接是根项目名,web资源的上下文配置maven自动配置了上下文连接:
在这里插入图片描述
只需要对应webapp下的目录即可,但是会发现路径对应了仍然找不到文件css,html,js等静态资源:
在这里插入图片描述
原因在于web.xml配置的DispatcherServlet<url-pattern>/</url-pattern>/表示DispatcherServlet会拦截除jsp的所有资源并解析(/*表示拦截所有资源),静态资源经过其解析后就不是所需要的了,因此静态资源不需要其解析。

方法一:更改拦映射路径
DispatcherServlet<url-pattern></url-pattern>的路径映射为*.form或者*.do就不会再拦截静态资源了。

方法二:服务器默认Servlet(defaultServlet)处理静态资源
.html,.css,.js,.png,.jpg等资源交由服务器默认的sevlet处理,如web.xml的·注释一:

  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.gif</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.png</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
  </servlet-mapping>

使用该方法不能再引入javax.servlet-apijar工具包了,会起冲突,造成DispatcherServlet处理异常。

方法三:DispatcherServlet实现对静态资源的放行

 <!--DispatcherServlet无法处理的交由默认servlet处理-->
 <mvc:default-servlet-handler default-servlet-name="default"></mvc:default-servlet-handler>

    <!--静态资源的放行,不拦截以下目录的资源-->
    <mvc:resources mapping="/css/** " location="classpath:**/css/" />
    <mvc:resources mapping="/templates/** " location="classpath:**/templates/" />
    <mvc:resources mapping="/js/** " location="/js/" />
    <mvc:resources mapping="/img/** " location="/img/" />

在这里插入图片描述
location属性可以通过classpath:或者file:声明位置。

上述两种方法不共存选取其中一个即可。

经过上面的配置,Spring MVC的基础环境就搭建好了,静态资源也可以访问:
在这里插入图片描述
在配置文件中我们经常看见fileclasspath这两个参数,其表示的意义:
file: xxx-xxx.xml在根目录下的配置文件。
classpath:xxx-xxx.xmlresources目录下的配置文件。

后端接口

后端接口主要是由控制器来完成的,控制器包含众多解析器,如上述的DispatcherServlet执行流程一样,众多解析器分工合作共同完成。
Spring MVC开发实战SSM环境搭建及后端接口简单实例

控制器定义

定义一个控制器才能对请求进行解析,一个控制器就必须包含上图的每个部分,有的需要声明,有的自主创建。
Spring MVC开发实战SSM环境搭建及后端接口简单实例
@Controller声明一个处理器,解析URI。具体看之前的文章Spring MVC框架基础知识当然也可以声明 @RestController

@RestController 注解,则 Controller 中的方法无法返回 jsp 或者 html 页面,配置的视图解析器 InternalResourceViewResolver 也不起作用,返回的内容就是 Return 里的内容。也就是只能返回数据。

@RestController注解,该类会被看成一个Controller,同时该类中所有使用@RequestMapping注解的方法都默认使用了@ResponseBody注解, getJson方法会将List集合数据转换成JOSN格式并返回客户端。

// 该类会被看成一个Controller
@RestController
@RequestMapping("/json")
public class BookController
{
	// 同时该类中所有使用@RequestMapping注解的方法都默认使用了@ResponseBody注解,
	// 所以getJson方法会将List集合数据转换成JSON格式并返回客户端。
	@RequestMapping(value = "/testRequestBody")
	public Object getJson()
	{
		List<Book> list = new ArrayList<Book>();
		list.add(new Book(1, "书名称1", "书的作者1"));
		list.add(new Book(2, "书的名称2", "书的作者2"));
		return list;
	}
}

@Controller既可以返回视图也可以返回数据。默认返回视图, 配合视图解析器返回指定视图,配合@ResponseBody注解,返回数据。

@RequestMapping声明处理器映射器,URI与方法的映射。
在这里插入图片描述
在这里插入图片描述

@GetMapping是一个组合注解,是@RequestMapping(method = RequestMethod.GET)的缩写。

@PostMapping是一个组合注解,是@RequestMapping(method = RequestMethod.POST)的缩写。
如下没有method属性:
在这里插入图片描述

value 属性
一个@Controller 所注解的类中,可以定义多个处理器方法。当然,不同的处理器方法 所匹配的 URI 是不同的。这些不同的 URI被指定在注解于方法之上的@RequestMapping 的 value 属性中。URI的请求 是相对于 Web 的根目录(由配置Tomcat服务器是上下文连接决定)。
method属性
用于对被注解方法所处理请求的提交方式进行限制,即只有满足该 method 属性指定的提交方式的请求,才会执行该被注解方法。Method 属性的取值为 RequestMethod 枚举常量。RequestMethod.GET RequestMethod.POST
Spring MVC开发实战SSM环境搭建及后端接口简单实例
若不指定 method 属性,则无论是 GET 还是 POST 提交方式,均可匹配 即对于请求的提交方式无要求。

headers 属性: 指定request中必须包含某些指定的header值,才能让该方法处理请求。
params属性:指定request中必须包含某些参数值时,才让该方法处理。

consumes属性: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;

produces属性: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回。

@ResponseBody控制器指定解析数据的注解。

获取请求参数

表单参数

  • application/json
    该类型的数据是最常用的数据传递的类型,只支持POST方法,servlet要用字符流接收。
doPost(HttpServletResquest request,....) throw HttpServletException,IoException{
	BufferedReader reader=request.getReader();
	String params = reader.readLine();
	//params的道德是json字符串,需要用第三方工具包将其转化为javaBean再进行操作
}

在这里插入图片描述
后端接收的是一个json字符串,需要共第三方工具包转换为javaBean或其他数据类型。

在Spring MVC框架中,用@RequestBody注解接收请求日的内容返回的是json字符串需要用第三方框架将json字符串转化为Java Bean。Spring MVC默认了jackson工具包,也可以使用第三方包fastjson

 <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.12.6</version>
    </dependency>

没导包会出现如下错误:
在这里插入图片描述

06-Mar-2022 08:57:41.773 警告 [http-nio-8080-exec-6] org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.logException Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json' not supported]
  • application/x-www-form-urlencoded
    表单提交的默认格式,不支持文件类型.它的请求格式是键值对。
    GET方法会将参数放在请求行传递,URL中可以看到。Spring MVC通过@RequestParam注解获取,如果参数名与声明的变量一致可省略注解。
@RequestMapping("/one")
    @ResponseBody
    public String one(@RequestParam("name") String name){
        return name;
    } //@RequestParam获取请求行参数


@RequestMapping("/two")
   @ResponseBody
   public String two(String name){
       return name;
   }  //当请求行参数于自定义参数一致是可省略注解

POST方法提交数据会封装到请求体中,以xxx=xxx的字符串类型传递。

<form action="/display" method="post">
    <input type="text" name="name"><br>
    <input type="text" name="address"><br>
    <button type="submit">提交</button>
</form>


@RequestMapping("/display")
   @ResponseBody
   public String five(@RequestBody String params){
       return  params;
   }

在这里插入图片描述

  • multipart/form-data
    上传文件的格式,以二进制传输,同文件上传章节。

  • text/plain
    text/plain是以纯文本格式(就是一段字符串)发送的. 如果你发送一个对象例如{ name:“leiwuyi”, age:12 }一定要对它做JSON.stringfiy()处理,否则将传送[object Object]

超链接数据

超连接主要有两种传递参数的方式,一种类似application/x-www-form-urlencoded格式后台获取的方式一致@RequestParam

<a href="http://localhost:8080/springMVC?type='news'&page=2"></a>

第二种是URI传参,使用@PathVariable获取模板参数:

<a href="http://localhost:8080/springMVC/page/2"></a>
//动态接收连接传递的参数
@RequestMapping(path="/page/{id}}", method=RequestMethod.GET)
public String page(@PathVariable("id") int id, Model model) {
    // 具体的方法代码…
}

还有类似下面的URI使用@MatrixVariable具体看之前的文章Spring MVC框架基础知识

<a href="http://localhost:8080/springMVC?/cars;color=red;year=2012"></a>

请求行数据

请求行参数就和上面的application/x-www-form-urlencoded一致。

请求头数据

请求头参数实在请求头中自定义key-value在接口通过@RequestHeader("key")来获取:

//http请求头中添加name=xwh,请求体中携带了{address:"beijing"}字符串
var obj={address:"beijing"};
    var jsonString=JSON.stringify(obj);
    //alert(jsonString);

    const xhr=new XMLHttpRequest();
    document.getElementById("btn3").onclick=function(){
        //alert("hello");
        xhr.open("POST", "http://localhost:8080/springMVC/book/header", true);
        xhr.setRequestHeader("name", "xwh");
        xhr.send(jsonString);

    }
//后端接口
    //请求头传递少量参数
    @RequestMapping("/header")
    public void seven(@RequestHeader("name") String name,@RequestBody String params){
        System.out.println("请求头携带参数name:"+name);
        System.out.println("请求体数据params:"+params);
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

请求体数据

在pom.xml中导包(框架默认使用jackson不需要引用,接口不用做任何修改):


<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.6</version>
</dependency>

如果用的是fastjson需要在接口处调用(先导fastjosn工具包):

@RequestMapping("/json")
    @ResponseBody
    //先以json字符串的方式接收在调用工具包的对象转化
    public Book six(@RequestBody String params){
    	//调用该方法将传入类型转化为声明类型
    	Book book = JSON.parseObject(params,Book.class);
    	//String param=JSON.toJsonString(args);将传入类型转化为json字符串
        return  book;
    }

此时如果在传错参数类型就会有以下错误提示

Unrecognized token ‘asdd’: was expecting (JSON String, Number, Array, Object or token ‘null’, ‘true’ or ‘false’);

Cannot deserialize value of type spring.model.Book from Array value (token JsonToken.START_ARRAY);

正确演示:

 //前端发送json字符串
 var obj={name:"xwh",address:"beijing"};
    var jsonString=JSON.stringify(obj);
    const xhr=new XMLHttpRequest();
    document.getElementById("btn1").onclick=function(){
        //alert("hello");
        xhr.open("POST", "http://localhost:8080/springMVC/book/json", true);
        xhr.setRequestHeader("Content-type", "application/json");
        xhr.send(jsonString);
    }
//后端默认jackson转化(需要导包)
@RequestMapping("/json")
    @ResponseBody
    public Book six(@RequestBody Book book){
        return  book;
    }

在这里插入图片描述
fastjson配置

<!-- 配置fastjson中实现HttpMessageConverter接口的转换器 -->
            <bean id="fastJsonHttpMessageConverter"
                class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
                <!-- 加入支持的媒体类型:返回contentType -->
                <property name="supportedMediaTypes">
                    <list>
                        <!-- 这里顺序不能反,一定先写text/html,不然ie下会出现下载提示 -->
                        <value>text/html;charset=UTF-8</value>
                        <value>application/json;charset=UTF-8</value>
                    </list>
                </property>
            </bean>

默认参数

除了上面请求携带的参数外控制器还有默认参数。

  • ➢HttpServletRequest
  • ➢ HttpServletResponse
  • ➢ HttpSession

其他注解参数

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
.

这些默认参数和servlet的用法一样。

请求参数中文乱码问题

以下配置是配置spring mvc的编码格式:
在这里插入图片描述
web.xml配置

 <!--过滤器-->
<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>
    <init-param>
        <param-name>forceRequestEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>forceResponseEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

在这里插入图片描述
如图响应头的编码是ISO-8859-1而编码格式是utf-8不一致造成乱码,可以修改响应头编码为utf-8或将jsp页面的解码格式改为utf-8即可。配置html或jsp的解码编码未utf-8:

html
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

其原理是请求的编码格式要和解码格式一致。

处理器方法的返回值

@Controller默认是响应视图,且是jsp视图,需要通过视图解析器进行配置,转发到对应视图。
@RestController只能返回数据作用单一。转发视图的的核心是配置视图解析器(路径和视图名,视图类型)

  • ➢ ModelAndView

若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时处理器方法返回 ModelAndView 比较好。如下处理器方法中定义 ModelAndView 对象:

@RequestMapping(value = "/student")
   public ModelAndView studentdo(Student student){
       ModelAndView mv = new ModelAndView();
       mv.addObject("name",student.getName());   //请求域存储参数
       mv.setViewName("/WEB-INF/hello.jsp");	//转发到指定视图
       System.out.println(student.getName());
       return mv;
    }

ModelAndView同时继承了Model接口和View接口,一个负责将转发的数据存储到请求域,一个负责转发到对应视图。Map和ModelMap都是Model的实现类,完成转存请求域的功能。View还有一个SmartView的接口需要实现。

@RequestMapping("/three")
    protected View eight(){
        View view =new View() {
            @Override
            public void render(Map<String, ?> map, javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
                //逻辑代码
            }
        }
        return view;
    }

所以这些接口都不作为返回类型而作为参数对ModelView进行配置。

  • ➢ String

处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址(字符串的拼接)

//逻辑视图
@Controller
public class viewCtrl {
    @RequestMapping("/display")
    public String five(@RequestBody String params){
        return  "index.jsp";
    }
}
 /dispaly/index.jsp  视图解析器会在该路径下寻找资源

//物理视图
@Controller
public class viewCtrl {
    @RequestMapping("/display")
    public String five(@RequestBody String params){
        return  "/index.jsp";
    }
}
//视图解析在上下文连接的路径下即根目录下寻找视图

视图查找机制物理视图默认在WEB-INF目录下查找return的视图,例如return "/templates/two.html"
会在WEB-INF下寻找templates下的two.html,如果没找到在WEB-INF的上级目录继续查找templates下的two.html一次递归知道找到,否则404。逻辑视图直接字符串拼接,[上下文]+/templates/two.html
例如 return "templates/two.html,会在loclahost:8080/[项目名]/templates/two.html。

  • ➢ 无返回值 void

没有返回值就可以当作普通HttpServlet处理。

  • ➢ 自定义类型对象

自定义额类型多样不利于前端解析,一般只传递JSON,List,Map等数据类型,当然这些数据需要先解析为String类型在发送,前端接收后同样也需要再复原,但像Ajax,axios等框架会自动复原。

自定义类型通过 @ResponseBody 注解,将转换后的 JSON 字符串放入到响应体中。将 Object 数据转化为 JSON 数据,需要由消息转换器 HttpMessageConverter 完成。而转换器的开启,需要由<mvc:annotation-driven/>来完成。转换器依赖Jackson工具包。需要导入依赖:

<dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.12.6</version>
    </dependency>

前端发送的数据需要转为json,并再请求头声明类型:

var obj={name:"xwh",address:"beijing"};
    var jsonString=JSON.stringify(obj);
    const xhr=new XMLHttpRequest();
    document.getElementById("btn1").onclick=function(){
        //alert("hello");
        xhr.open("POST", "http://localhost:8080/springMVC/book/json", true);
        xhr.setRequestHeader("Content-type", "application/json");
        xhr.send(jsonString);
    }

后端通过jackson工具自动解析为声明的类型(默认工具只需要引入,无需配置):

//共调用两次工具解析
 @RequestMapping("/json")
    @ResponseBody
    public Book six(@RequestBody Book book){   //第一次获取请求数据时解析为声明类型
        System.out.println(book);
        return  book;   //响应数据时调用解析转为String打印出来是一样的
    }

再上面的/json接口将前端发送的数据又返回给前端,再传递的过程中数据没有变化,变化的只有数据类型。

后台打印的Book类型:
在这里插入图片描述
前端响应json字符串(ajax,axios的回调函数会自动将json字符串转化为json,但是需要在响应头中声明Content-Type:application/json这个声明只可选择枚举的类型,前端支持的类型)。
在这里插入图片描述

处理器的响应传值

返回值类型是ModelAndView它有图上的方法来向请求域中添加参数,key-value类型。在这里插入图片描述
返回值是其他类型通过Model接口或Model接口的实现类ModelMap来实现(用来处理数据转发的接口)。该类或接口只起对象的作用用来携带参数:
在这里插入图片描述
在这里插入图片描述

@RequestMapping("/three")
    protected String eight(Model model ){
        model.addAttribute("name","xwh");
        return "/index.jsp";
    }

在这里插入图片描述

常用注解

在这里插入图片描述
Spring MVC常用注解感谢作者@蓝蓝的读书笔记笔记库
在这里插入图片描述
@RequestPart注解用于绑定multipart/form-data参数,即文件类型。

页面转发

页面转发

@CrossOrigin注解解决跨域问题

原文连接
在这里插入图片描述

@CrossOrigin(maxAge=3600)
@Controller
public class CrossoriginController
{
    ...
}

表示CrossOriginController控制器的所有方法可以处理http://www.fkit.org域上的请求:

@CrossOrigin(
    origins="http://www.fkit.org",
    maxAge=3600
)
@Controller
public class CrossOriginController
{
    ....
}

@CookieValue注解

注解用于将请求的Cookie数据映射到请求处理方法的形式参数上。使用@CookieValue注解可指定如下表所示的属性:
在这里插入图片描述

package org.fkit.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class CookieValueController
{
	// 测试@CookieValue注解
	// 该方法映射的请求为 /cookieValueTest
	@GetMapping(value = "/cookieValueTest")
	// 将cookie中的JSESSIONID值赋值给方法的参数sessionId
	public void cookieValueTest(
			@CookieValue(value = "JSESSIONID", defaultValue = "") String sessionId)
	{
		System.out.println("通过@CookieValue获得JSESSIONID: " + sessionId);
	}
}

@RequestAttribute

注解用于访问由请求处理方法、过滤器或拦截器创建的、预先存在于request作用域中的属性,并将该request作用域中的属性的值设置到请求处理方法的形式参数上。
在这里插入图片描述

@RequestMapping(value="/arrtibuteTest")
public void arrtibuteTest(
    @RequestAttribute(value="username") String username){ ... }

以上代码会自动将request作用域中名为username的属性的值设置到username参数上。

@SessionAttribute

注解用将session作用域中的属性赋值给目标方法的形式参数,这些属性由请求处理方法、过滤器或拦截器创建并存在于session作用域中。
在这里插入图片描述

@RequestMapping(value="/arrtibuteTest")
public void arrtibuteTest(
    @SessionAttribute(value="username") String username) {...}

以上代码会自动将session作用域中名为username的属性的值设置到请求处理方法的username形式参数上。

@SessionAttributes

注解允许我们有选择地指定Model中的哪些属性转存到HttpSession对象当中。
在这里插入图片描述

package org.fkit.controller;

import org.fkit.domain.User;
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.bind.annotation.SessionAttributes;

@Controller
// 将Model中名为user的的属性转存HttpSession对象当中
@SessionAttributes("user")
public class SessionAttributesController
{

	// 该方法映射的请求为http://localhost:8080/SessionAttributesTest/login
	// 把表单提交的请求参数loginname赋值给方法的loginname参数
	@RequestMapping(value = "/login")
	public String login(@RequestParam("loginname") String loginname,
	        @RequestParam("password") String password, Model model)
	{
		// 创建User对象,装载用户信息
		User user = new User();
		user.setLoginname(loginname);
		user.setPassword(password);
		user.setUsername("admin");
		// 将user对象添加到Model当中
		model.addAttribute("user", user);
		// 浏览器端重定向到其他请求处理方法,这样会重新生成一个请求对象
		// 因为是新的对象,所以request作用域内将不再存在user属性
		return "redirect:/sessionScope";
	}
	@RequestMapping(value = "/sessionScope")
	public String sessionScope()
	{
		return "welcome";
	}
}

异常处理

Controller的请求处理方法中手动使用try… catch块捕捉异常,当捕捉到特定异常时,返回特定逻辑视图名,但这种处理方式非常烦琐,需要在请求处理方法中书写大量的catch块。

  • servlet的配置文件web.xml处理错误页面:
<error-page>
    <error-code>404</error-code>
    <location>/error.html</location>
  </error-page>
  
  <error-page>
    <error-code>500</error-code>
    <location>/base.html</location>
  </error-page>

这种方法过于笼统不利于处理多类型的错误。

<error-page>
    <exception-type>Exception</exception-type>
    <location>/error.html</location>
  </error-page>

这种对Java异常的处理,需要熟悉各种异常的类,也不便于处理。

  • Spring MVC中提供的异常处理方式有两种:
  1. 使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver
 <!-- p:defaultErrorView="error"表示所有没有指定的异常都跳转到异常处理页面error, -->
    <!-- p:exceptionAttribute="ex"表示在异常处理页面中可以访问的异常对象变量名是ex。 -->
    <bean
        class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"
        p:defaultErrorView="error" p:exceptionAttribute="ex">

        <!-- 异常映射 exceptionMappings表示映射的异常, -->
        <!-- 接受参数是一个Properties key是异常类名,value是处理异常的页面 -->
        <property name="exceptionMappings">
            <props>
                <prop key="IOException">ioerror</prop>
                <prop key="SQLException">sqlerror</prop>
            </props>
        </property>
    </bean>

重点是异常处理的配置。 SimpleMappingExceptionResolver是Spring提供的处理异常的类,所有抛岀的异常都会被该类捕获。

  1. ExceptionHandlerExceptionResolver异常处理器,使用@ExceptionHandler注解实现局部异常处理或使用@Controlleradvice注解实现统一异常处理或@ResponseStatus处理http异常。这两个是实现ExceptionHandlerExceptionResolver

@ResponseStatus注解是处理异常最简单的方式,其可以修饰一个类或者一个方法,当修饰一个类的时候,通常修饰的是一个异常类。
在这里插入图片描述
使用时,先声明一个自定义异常类,在自定义异常类上面加上@ResponseStatus注解,就表示在系统运行期间,当抛出自定义异常的时候,使用@ResponseStatus注解中声明的value属性和reason属性将异常信息返回给客户端,

@ExceptionHandler注解作用对象为方法,并且在运行时有效,value()可以指定异常类。@ExceptionHandler注解的方法可以支持的参数除了HttpServletRequest、HttpServletResponse等对象之外,还支持一个异常参数,包括一般的异常或自定义异常。


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class TestController
{
	@GetMapping("/test")
	public String test() throws Exception
	{
		// 模拟异常,调用本类中定义的异常处理方法
		@SuppressWarnings("unused")
		int i = 5 / 0;
		return "success";
	}
	// 在异常抛出的时候,Controller会使用@ExceptionHandler注解的方法去处理异常
	// value=Exception.class表示处理所有的Exception类型异常。
	@ExceptionHandler(value = Exception.class)
	public ModelAndView testErrorHandler(Exception e)
	{
		ModelAndView mav = new ModelAndView();
		mav.setViewName("error");
		mav.addObject("ex", e);
		return mav;
	}
}

@ExceptionHandler注解, value = Exception.class表示处理所有的Exception类型异常。当TestController类抛出异常的时候,会使用@ExceptionHandler注解的方法去处理异常,而不会直接抛给浏览器。 testErrorHandler()方法将捕捉到的异常对象保存到ModelAndView当中,传递到JSP页面。

基于Controller的@ExceptionHandler注解方法在进行异常处理时,对于每个Controller都需要写@ExceptionHandler注解的异常处理方法,在实际开发当中这非常烦琐。可以写一个父类,在父类中完成@ExceptionHandler注解的异常处理方法,所有的Controller继承这个父类,则所有的Controller就都拥有了@ExceptionHandler注解的异常处理方法。

//父类Exception

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
public class BaseExceptionController
{
	// 表示这是一个异常处理方法
	// value = Exception.class表示处理的异常类型为Exception
	// 也就是处理所有的异常
	@ExceptionHandler(value = Exception.class)
	public ModelAndView defaultErrorHandler(Exception e) throws Exception
	{
		ModelAndView mav = new ModelAndView();
		// 设置模型数据
		mav.addObject("ex", e);
		// 设置视图
		mav.setViewName("error");
		return mav;
	}
}


//子类Exception

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class UserController extends BaseExceptionController
{
	@GetMapping("/login")
	public String login(String username) throws Exception
	{
		if (username == null)
		{
			// 调用本类的异常处理方法
			throw new NullPointerException("用户名不存在!");
		}
		return "success";
	}
}

@ControllerAdvice注解该注解使用@Component注解,也就是说可以使用<context: component-scan>扫描该注解。 Spring官方文档说明,扫描到@Controlleradvice注解之后,会将@ControllerAdvice注解修饰的类的内部使用@ExceptionHandler、@InitBinder、@ModelAttribute注解的方法应用到所有的请求处理方法上。


import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

// GlobalExceptionHandler类使用了@ControllerAdvice注解来修饰,
// 其会被<context:component-scan>扫描,
// 这使得该类中使用@ExceptionHandler注解修饰的方法都被应用到所有请求处理方法上
// 也就是所有请求处理方法抛出的异常都将由该类中对应的@ExceptionHandler注解修饰的方法处理.
@ControllerAdvice
public class GlobalExceptionHandler
{
	// 处理Exception类型异常
	@ExceptionHandler(value = Exception.class)
	public ModelAndView globalErrorHandler(Exception e) throws Exception
	{
		ModelAndView mav = new ModelAndView();
		mav.addObject("ex", e);
		mav.setViewName("error");
		return mav;
	}
	// 处理OrderException自定义异常
	@ExceptionHandler(value = OrderException.class)
	// 返回的结果将会被封装成JSON数据,并返回给客户端
	@ResponseBody
	public Object OrderErrorHandler(Exception e) throws Exception
	{
		// 创建返回对象Map并设置属性,会被@ResponseBody注解转换为JSON返回
		Map<String, Object> map = new HashMap<>();
		map.put("code", 100);
		map.put("message", e.getMessage());
		map.put("data", "请求失败");
		return map;
	}
}

GlobalExceptionHandler类使用了@ControllerAdvice注解来修饰,则该类会被<context: component-scan>扫描,该类中使@ExceptionHandler注解修饰的方法将被应用到所有请求处理方法上。

@RestControlleradvice注解org.springframework.web.bind.annotation.RestControlleradvice注解本身使用@ControllerAdvice@ResponseBody注解。使用了@RestControllerAdvice注解的类会被看作一个@ControllerAdvice,而该类中所有使用@ExceptionHandler注解的方法都默认使用@ResponseBody注解。

package org.fkit.controller;

import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @RestController注解本身使用@ControllerAdvicer和@ResponseBody注解。
 * 使用了@RestControllerAdvice注解的类会被看作一个ControllerAdvicer,
 * 而该类中所有使用@ExceptionHandler注解的方法都默认使用了的@ResponseBody注解。
 */
@RestControllerAdvice
public class GlobalExceptionHandler
{
	// 处理OrderException自定义异常
	@ExceptionHandler(value = OrderException.class)
	// 默认使用了的@ResponseBody注解,会将方法返回的Map转换为JSON数据发送给浏览器
	public Object OrderErrorHandler(Exception e) throws Exception
	{
		// 创建返回对象Map并设置属性,会被@ResponseBody注解转换为JSON返回
		Map<String, Object> map = new HashMap<>();
		map.put("code", 100);
		map.put("message", e.getMessage());
		map.put("data", "请求失败");
		return map;
	}
}

在实际开发中@ExceptionHandler注解的功能最强大。异常处理

文件上传

Spring MVC的文件上传十分方便不同于于Servlet上传需要写大量配置,因为它直接提供了对文件上传的直接支持即MultipartResolver接口。该接口用于处理上传请求,并将上传的数据包装成可以直接获取的文件。

MultpartiResolver接口有以下两个实现类:

  • StandardServletMultipartResolver:使用了 Servlet 3.0 标准的上传方式。
  • CommonsMultipartResolver:使用了 Apache 的 commons-fileupload commons-io=来完成具体的上传操作。

MultpartiResolver接口具有以下方法。
在这里插入图片描述

使用 CommonsMultipartResolver来完成文件上传,分为单文件上传和多文件上传两部分介绍:

  • 单文件上传
  1. 导入依赖

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.2.2</version>
</dependency>
  1. 配置 MultipartResolver
<!-- 配置MultipartResolver,用于上传文件,使用spring的CommonsMultipartResolver -->
<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="5000000" />
    <property name="defaultEncoding" value="UTF-8" />
</bean>

<!--defaultEncoding:请求的编码格式,默认为 ISO-8859-1,此处设置为 UTF-8
(注:defaultEncoding 必须和 JSP 中的 pageEncoding 一致,以便正确读取表单的内容)。-->
<!--maxUploadSize:上传文件大小上限,单位为字节。-->

在这里插入图片描述

resolveLazily:延迟解析,默认为false--立即解析multipart request;

defaultEncoding:解析请求的默认字符编码 ; 默认值为"ISO-8859-1"。通常设置为"UTF-8";

maxUploadSize:文件上传最大值; 默认值为 -1(表示没有限制);

maxUploadSizePerFile:每个文件上传最大值;默认值为 -1(表示没有限制);

maxInMemorySize:存储在内存的最大值;默认值为10240B(10KB);

uploadTempDir:上传文件的临时目录;默认值为WEB应用程序的临时目录;

servletContext:the servletContext to use;

  1. 文件上传表单页面

表单的文件上传需要使用 enctype 属性,并将它的值设置为 multipart/form-data,同时将表单的提交方式设置为 post。

<!--负责文件上传表单的编码类型必须是“multipart/form-data”类型。-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/springOne/view/getFile" method="post" enctype="multipart/form-data">
    <input type="file" name="fileInfo">
    <input type="text" name="description">
    <button type="submit">上传</button>
</form>

</body>
</html>
  1. 创建文件的映射对象POJO类

在该 POJO 类中声明一个 MultipartFile即(前端的uplaodaFile)类型的属性封装被上传的文件信息,属性名与前端页面 <input type=file name="myfile">name属性的相同,代码如下:

import org.springframework.web.multipart.MultipartFile;

public class File {
    private String description;
    private MultipartFile fileInfo;
}
  1. 编写文件上传的控制器
//测试是否可以传递到后端
@PostMapping("/getFile")
    protected String uploadFile(String description, MultipartFile fileInfo){
        System.out.println(description);
        System.out.println(fileInfo);
        return "success";
    }

在这里插入图片描述
如图所示文件成功传递到后端,调用MultpartiResolver接口的方法对其解析和转存即可。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
File类型是java内置处理文件的。

解析并存储的代码:

@PostMapping("/getFile")
@ResponseBody
    protected String uploadFile(String description, MultipartFile fileInfo, HttpServletRequest request) {
        //System.out.println(description);
        //System.out.println(fileInfo);
        //获取原始名,目的时获取后缀名
        String originalFileName=fileInfo.getOriginalFilename();
        //获取后缀名
        String extensionName=originalFileName.substring(originalFileName.lastIndexOf("."));

        System.out.println(extensionName);

        //生成随机文件名,避免上传的文件同名,时间戳加随机数
        //String.valueOf(new Date().getTime());
        //String.valueOf(Math.random()*100);
        String newName=String.valueOf(new Date().getTime())+String.valueOf(Math.random()*100);

        System.out.println(newName);

        //生成完整文件名,如:23482493242.jpg
        String finallyName=newName+extensionName;

        System.out.println(finallyName);

        //获取需要转存的位置即服务器的路径
        //controller继承的HttpServlet携带两个基本参数(res,resp)
        //spring MVC默认的路径时WEB-INF,如果没有会向上查找
        String dirname=request.getServletContext().getRealPath("imgs");

        String savePath=dirname+"/"+finallyName;
        
        System.out.println(savePath);
        //保存文件
        try {
            fileInfo.transferTo(new File(savePath));
        }catch (IOException e){
            e.printStackTrace();
            System.out.println("save error");
        }

        return "success";
    }


后台输出结果:
在这里插入图片描述
在这里插入图片描述
处理处理文件解析与保存的过程中除了Spring MVC提供的接口的方法外主要就是String dirname=request.getServletContext().getRealPath("imgs");请求中的这个方法了,看源代码配置:

private File getCommonDocumentRoot() {
		for (String commonDocRoot : COMMON_DOC_ROOTS) {
			File root = new File(commonDocRoot);
			if (root.exists() && root.isDirectory()) {
				return root.getAbsoluteFile();
			}
		}
		return null;
	}
private static final String[] COMMON_DOC_ROOTS = { "src/main/webapp", "public",
			"static" };

request.getServletContext().getRealPath()返回的是一个临时文件夹的绝对地址,会根据服务器地址变化,例如,小编在调用是获取的本机地址是E:JavaWeb\xxx\...\webapp\imgs如上面dirname传递的参数是imgs那么就会映射到该目录(首先要存在)。正如源代码配置的一样该地址默认映射到项目的webapp目录。

简单说该临时地址由三部分组成:项目所在位置的绝对地址+src/main/webapp+参数。第一部分随项目部署的位置改变。

文件下载

浏览器支持多种文件的解析和存储,因此下载文件只需要接口提供数据流。(以图片文件为例)

文件下载只能是异步请求,通过Ajax发送请求获取服务器图片目录下所有图片地址,显示在前端页面上:

获取服务器文件名

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../js/axios.min.js"></script>
</head>
<body>
<h1>bookShow</h1>

<button type="button" id="btn3" >set header</button><!--οnclick="alert('hello')"-->
<script>
    document.getElementById("btn3").onclick=function(){
        axios({
            method:'get',
            url:'http://localhost:8080/springOne/view/download',
        }).then(function(response){
            console.log(response.data);
        })
    }


</script>


</body>
</html>
//文件下载
    @GetMapping("/download")
    @ResponseBody
    protected String[] downloadFile(HttpServletRequest request,HttpServletResponse response){
        //从imgs目录下获取所有图片,并响应前端
        String dirname=request.getServletContext().getRealPath("imgs");

        //img是一个目录本身也是java的File对象,通过该对象的接口获取所有图片的名称
        File imgFileName=new File(dirname);

        //返回文件夹下所有图片名称
        String [] nameList=imgFileName.list();
        return nameList;
    }

返回图片名称与服务器目录下一致:
在这里插入图片描述
在这里插入图片描述
前端能够拿到数据后,将数据可视化,并为每个图片提供下载按钮,这个按钮发送异步请求,这时返回的就是数据流了,由浏览器解析。

可视化图片并提供下载功能

//使用bootstrap框架对数据解析
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../js/jquery.js"></script>
    <script src="../js/axios.min.js"></script>
    <script src="../js/bootstrap.min.css"></script>
    <link rel="stylesheet" href="../css/bootstrap.min.css">
</head>
<body>


    <div class="row" id="container">

    </div>

    <script>
        axios({
    method:'get',
    url:'http://localhost:8080/springOne/view/download',
    //responseType:'stream'
    }).then(function(response){
    //console.log(response.data);
        for(var i=0; i<response.data.length; i++){
            var addPicHtml="<div class='col-sm-6 col-md-4 col-sm-4 col-xs-6' style='width:200px'><div class='thumbnail'><img src='/springOne/imgs/"+response.data[i]+"' alt='...' width='100%'><div class='caption'><p><a href='#' class='btn btn-primary' role='button'>下载</a></p></div></div></div>";
            //document.getElementById("container").innerHTML = addPicHtml;
            $("#container").append(addPicHtml);
        }
    })
    </script>
</body>
</html>

在这里插入图片描述

下载功能实现

浏览器可以自主解析图片文件,后端接口提供图片的数据流即可,也是异步请求:
在这里插入图片描述
如上面的gif中上传后鼠标移动到下载后左下角地址的变化,将图片名称通过url传递给后端接口。
在可视化图片时已经获取了图片名称,将图片名称传到下载API通过名称找到图片传回数据流:

//传输图片数据流
@GetMapping("/imgbases")
public void imgBase(@RequestParam("img") String imgName ,HttpServletRequest request,HttpServletResponse response){
    //获取图片目录
    String dirname=request.getServletContext().getRealPath("imgs");
    //获取图片文件路径
    String filePath=dirname+"/"+imgName;

    //图片的输出流(内存中)
    try{
        FileInputStream inputStream=new FileInputStream(filePath);

        //图片数据流浏览器可以直接识别,设置响应头,让浏览器无法识别,从而调用保存接口
        response.setContentType("application/unknown");
        //把文件名也传递过去,保存的时候需要,专门接口的响应头,不是普通响应头
        response.addHeader("Content-Disposition","attachment;filename="+imgName);

        //使用commons-io的流处理将数据流写入响应体
        IOUtils.copy(inputStream,response.getOutputStream());

    }catch (IOException e){
        e.printStackTrace();
    }


}

上面的代码已经将图片数据流发送给前端,response.setContentType()方法将响应内容设置为浏览器无法解析的对象,这样就会调用保存的系统接口,同时把文件名也传过去,便于保存。(如果没有两步设置,点击下载会发现图片会打开而不是调用保存接口,这是由于浏览器能够解析图片文件,不会直接调用系统保存文件接口。在响应头设置其为无法识别的接口就可以直接存储了。

在这里插入图片描述

拦截器

Servlet中存在过滤器,Spring IoC容器中存在拦截器,它们有很大差异:

在这里插入图片描述

  1. 过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
  2. 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,因为拦截器是spring提供并管理的,spring的功能可以被拦截器使用,在拦截器里注入一个service,可以调用业务逻辑。而过滤器是JavaEE标准,只需依赖servlet api ,不需要依赖spring。
  3. 过滤器的实现基于回调函数。而拦截器(代理模式)的实现基于反射。
  4. Filter是依赖于Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在Spring的任何情况下使用。
  5. Filter的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。

在Servlet开发中,每个请求对应一个Servlet,因此可以通过Filter管理;但在Spring MVC中,只有一个DispatcherServlet,通过映射来访问Filter不再满足需求,需要通过Ierceptor(拦截器来实现)。

在 Spring MVC 框架中定义一个拦截器需要对拦截器进行定义和配置,主要有以下 2 种方式。

  1. 通过实现HandlerInterceptor接口或继承 HandlerInterceptor接口的实现类(例如
    HandlerInterceptorAdapter)来定义;
//首先是实现接口
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class TestInterceptor implements HandlerInterceptor {

    @Override
    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行");
    }
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle方法在控制器的处理请求方法调用之前执行");
        return true;
    }   /******注意return true 放行******/
    
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("afterCompletion方法在控制器的处理请求方法执行完成后执行,即视图渲染结束之后执行");
    }
}


//控制器映射
@RequestMapping(value = "/three",produces = "application/html;charset=utf-8")
    protected String eight(Model model){
        model.addAttribute("name","张三");

        return "/index.jsp";
    }

<!--通过配置文件对three接口拦截-->
<mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/view/three"/>
            <bean class="spring.controller.Interceptor.MyInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

<!--
多个拦截器会构成拦截器链,按配置顺序拦截
-->

结果:
在这里插入图片描述

在这里插入图片描述

<!-- 配置拦截器 -->
<mvc:interceptors>
    <!-- 配置一个全局拦截器,拦截所有请求 -->
    <bean class="net.biancheng.interceptor.TestInterceptor" /> 
    <mvc:interceptor>
        <!-- 配置拦截器作用的路径 -->
        <mvc:mapping path="/**" />
        <!-- 配置不需要拦截作用的路径 -->
        <mvc:exclude-mapping path="" />
        <!-- 定义<mvc:interceptor>元素中,表示匹配指定路径的请求才进行拦截 -->
        <bean class="net.biancheng.interceptor.Interceptor1" />
    </mvc:interceptor>
    <mvc:interceptor>
        <!-- 配置拦截器作用的路径 -->
        <mvc:mapping path="/gotoTest" />
        <!-- 定义在<mvc:interceptor>元素中,表示匹配指定路径的请求才进行拦截 -->
        <bean class="net.biancheng.interceptor.Interceptor2" />
    </mvc:interceptor>
</mvc:interceptors>

在这里插入图片描述

  1. 通过实现WebRequestInterceptor 接口或继承WebRequestInterceptor 接口的实现类来定义。

WebRequestInterceptor和HandlerInterceptor接口中定义的方法作用也是一样的。不同点是
WebRequestInterceptor的入参WebRequest是包装了HttpServletRequest 和HttpServletResponse的,通过WebRequest获取Request中的信息更简便。其次preHandle是没有返回值的,说明该方法中的逻辑并不影响后续的方法执行,所以这个接口实现就是为了获取Request中的信息,或者预设一些参数供后续流程使用。

SSM整合

Maven创建web项目,并配置Tomcat。

添加war的打包依赖,导入servlet和jsp依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>ssm</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
		<dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
        </dependency>
    </dependencies>

</project>

Mybatis配置

添加持久层框架时不要忘了对应的数据库驱动工具包。

  • 导入mybatis依赖
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.11</version>
</dependency>

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.5</version>
</dependency>
  • 创建mybatis-config.xml用于创建SqlSessionFactory

文件不需要任何配置,在IoC容器中通过MapperScannerConfigurer对象配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!--DataResource配置-->
	<!--Mapper.xml配置-->
</configuration>

Spring MVC整合Mybatis依赖于Ioc容器,像DataSource,SqlSessionFactory,SqlSession,Mapper等对象都可以交给IoC容器管理。同时Spring AOP提供了声明式事务管理,更加方便。

部署Spring、Spring MVC

  • 添加依赖
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.1.19.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.1.19.RELEASE</version>
    </dependency>

    <!--jdbc的orm用于整合其他持久层框架-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.1.19.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.1.19.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.1.19.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.1.19.RELEASE</version>
    </dependency>

	<!--spring默认解析数据的工具,导入即用无需配置-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.12.3</version>
    </dependency>


  • 创建配置文件

如果所有配置文件都集中在一个xml中会过于冗余,使用多配置文件分开管理(并不是独立的分工合作):

beans.xml配置注解声明,以及bean管理。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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/context
       http://www.springframework.org/schema/context/spring-context.xsd">


        <context:annotation-config></context:annotation-config>
        <context:component-scan base-package="cms.ssm"></context:component-scan>
</beans>

spring-servlet.xml文件进行mvc相关配置,如静态资源,拦截器,视图解析器,异常处理等。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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">

    <!--开启mvc注解驱动-->
    <mvc:annotation-driven></mvc:annotation-driven>

</beans>

mybatis-config.xml进行Mybatis的配置。

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

</configuration>

spring-mybatis.xml进行spring于mybatis整合配置。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

</beans>

web.xml配置Spring MVC的控制器。

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>


  <servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <!--服务器启动加载web.xml文件contextConfigLocation用于加载spring相关配置文件-->
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:spring-*.xml</param-value>
        </init-param>
    <!--classpath映射为resources目录下,file映射为根目录下   spring-*标识加载所有以此开头的文件-->


    <load-on-startup>1</load-on-startup>


  </servlet>
  <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

在web.xml中配置contextConfigLocation对象并配置路径,就会加载配置文件并启动IoC容器,不需要再java代码中通过ClassPathApplicationContext等上下文对象再次加载。

Spring整合Mybatis

上面的配置实现了spring配置文件到控制器的整合,接下来实现spring于mybatis的整合。

  • 导入mybatis-spring依赖
 <!--mybatis与spring结合-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>
  • 配置连接池,这里使用druid
<!--德鲁伊连接池-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.2.6</version>
    </dependency>
  • 配置基于jdbc的连接池的参数
druid.driver=com.mysql.cj.jdbc.Driver
druid.url=jdbc:mysql://localhost:3306/${数据库名}?characterEncoding=utf-8
druid.username=${username}
druid.password=${password}

#连接处参数
druid.pool.init=1
druid.pool.minIdle=3
druid.pool.maxActive=20
druid.pool.timeout=30000
  • 在spring-mybatis.xml文件配置数据源
<!--导入配置信息-->
    <context:property-placeholder location="classpath:druid.properties"></context:property-placeholder>
    <!--基于IoC容器创建数据源DataResource-->
    <bean id="druidDataResource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${druid.driver}"></property>
        <property name="url" value="${druid.url}"></property>
        <property name="username" value="${druid.username}"></property>
        <property name="password" value="${druid.password}"></property>

        <property name="initialSize" value="${druid.pool.init}"></property>
        <property name="minIdle" value="${druid.pool.minIdle}"></property>
        <property name="maxActive" value="${druid.pool.maxActive}"></property>
        <property name="maxWait" value="${druid.pool.timeout}"></property>
    </bean>
    <!--赋值表达式会自动将导入的配置信息按名称赋给对应属性-->
  • 在spring-mybatis.xml文件配置SqlSessionFactory
 <!--生产mybatis-spring提供的SqlSessionFactoryBean接收mybatis的SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--SqlSessionFactory中需要配置Mapper和DataResource-->
        <property name="dataSource" ref="druidDataResource"></property>
        <property name="mapperLocations" value="classpath:mapper/*.xml"></property>
        <!--设置POJO的包名,typeAliasesPackage指定POJO包名,mapper.xml的resultType,parameterType就不需要写全限定名了-->
        <property name="typeAliasesPackage" value="cms.ssm.model"></property>
    </bean>

	 <!--扫描dao包下的全部接口,并交由IoC容器管理-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
        <!--指定Mapper接口的包名-->
        <property name="basePackage" value="cms.ssm.dao"></property>
    </bean>

第一个bean实现注入xml文件并创建SqlSessionFactory,第二个bean负责生产basePackage包下的所有Mapper类并注入sql语句,返回SqlSessiongetMapper()等方法返回的Mapper类。

  • 在spring-mybatis.xml文件配置事务管理
 <!--声明式事务事务管理,配置事务管理器-->
    <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
        <property name="dataSource" ref="druidDataResource"></property>
    </bean>
    <!--开启事务注解扫描-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

将配置文件交给sping加载,最好不要交给springMVC加载 避免出现错误,因为web.xml配置时spring的监听先启动,springMVC的Dispatcherservlet接收到请求时初始化springMVC的配置文件。

测试是否配置成功

  • resources的mapper中创建UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cms.ssm.dao.UserMapper">
    <select id="allUser" resultType="User"> <!--mapper.xml文件导入到了IoC容器,resultTyoe直接从容器中获取-->
        select *
        from user
  </select>
</mapper>
  • dao中创建UserMapper.java的映射接口
public interface UserMapper {
    List<User> allUser();
}
  • 基于spring test创建单元测试

在test目录下创建UserMapperTest的测试文件,内容如下

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring-context.xml","classpath:spring-mybatis.xml","classpath:spring-servlet.xml"})
public class UserMapperTest {

    @Resource
    private UserMapper userMapper;
    @Test
    public void allUser() {
        List<User> list=userMapper.allUser();
        System.out.println(list);
    }
}

数据表:
在这里插入图片描述
测试的时候遇到如下错误:
在这里插入图片描述
在properties文件url后添加&useSSL=false&serverTimezone=GMT%2B8

druid.url=jdbc:mysql://localhost:3306/db1?characterEncoding=utf-8

druid.url=jdbc:mysql://localhost:3306/db1?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8

主要原因式数据库驱动版本过低,mysql8.0Driver变更由com.mysql.jdbc.Driver更新为com.mysql.cj.jdbc.Driver,更改连接URL,设置useSSL=false。更改连接URL,增加服务器时区值配置serverTimezone=GMT%2B8GMT%2B8表示时区东八区

开始也是这个问题看了这个博客的解析,更改后就没问题了。初始化数据库错误,init datasource error, url: jdbc:mysql://localhost:3306/

在这里插入图片描述
需要注意的是测试类中需要使用注解加载spring及spring mvc相关文件,当配置了Tomcat后配置文件在web.xml中就加载了,由Tomcat初始化。

配置Tomcat实现后端后端接口

编写控制器

@Controller
public class Login {
    @Resource
    private UserMapper userMapper;

    @RequestMapping(value = "/user",method = RequestMethod.GET)
    public String identify(Model model){
        List<User> list=userMapper.allUser();
        model.addAttribute("list",list);
        return "index.jsp";
    }
}

jsp作为显示页面

<%@ page isELIgnored="false" %>
<html>
<body>
<h2>Hello World!</h2>
${list}
</body>
</html>

配置并启动服务器,浏览器访问接口
在这里插入图片描述

案例解压后直接运行,免费下载!有一个对象相信会更快搭建ssm环境。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/156312.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!