小工具      在线工具  汉语词典  dos游戏  css  js  c++  java

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

# Spring,后端,spring,mvc,javaee 额外说明

收录于:17天前

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)执行完成后,返回一个ModelAndView对象给DispatcherServlet。

  • 根据返回的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的基础环境就搭建好了,静态资源也可以访问:
在这里插入图片描述
在配置文件中我们经常看见文件类路径这两个参数,其表示的意义:
file: xxx-xxx.xml在根目录下的配置文件。
classpath:xxx-xxx.xmlresources目录下的配置文件。

后端接口

后端接口主要是由控制器来完成的,控制器包含众多解析器,如上述的DispatcherServlet执行流程一样,众多解析器分工合作共同完成。

控制器定义

必须定义一个控制器来解析请求。控制器必须包含上图的每个部分。有些需要声明,有些可以独立创建。

@控制器声明一个处理器,解析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

若不指定 method 属性,则无论是 GET 还是 POST 提交方式,均可匹配 即对于请求的提交方式无要求。

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

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

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

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

获取请求参数

表单参数

  • 应用程序/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]
  • 应用程序/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;
   }

在这里插入图片描述

  • 多部分/表单数据
    上传文件的格式,以二进制传输,同文件上传章节。

  • 文本/纯文本
    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>

默认参数

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

  • ØHttpServlet请求
  • Ø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"%>

原则是请求的编码格式必须与解码格式一致。

处理器方法的返回值

@控制器默认是响应视图,且是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){
     ... }

上面的代码会自动将请求范围内名为 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的功能可以被拦截器使用。将服务注入拦截器即可调用业务逻辑。 Filter是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框架中定义拦截器需要定义和配置拦截器。主要有两种方式。

  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配置文件集成到controller中,进而实现了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>

把配置文件交给spring来加载,最好不要加载到springMVC中,以免出错,因为spring的监控是在配置web.xml时首先启动的,而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 测试创建单元测试

在测试目录中创建 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表示时区东八区

开始也是这个问题看了这个博客的解析,更改后就没问题了。初始化数据库错误,初始化数据源错误,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环境。

. . .

相关推荐

额外说明

Lambda 六种语法格式

  //左侧: Lambda 表达式的参数列表 //右侧: Lambda 表达式中所需执行的功能,即Lambda体   package com.lm; import org.junit.Test; import java.util.*; import

额外说明

vue v-for循环

  保证:key的唯一,提升渲染的效率,提升性能  

额外说明

Spring学习详细笔记(持续改进...)

概述 SSM框架是目前常用的框架,那框架是什么勒,简单来说,框架就是别人已经写好的软件,已经写好了模板,简化我们开发。后续我们如果需要进行其他开发,只需要进行一些增加删除。 SSM框架分别为: Spring:service处理框架,主要进行创建对象以及进

额外说明

企业级实战——品优购电商系统开发-17.18.创建数据库表与工程搭建

QQ 1274510382 Wechat JNZ_aming 商业联盟 QQ群538250800 技术搞事 QQ群599020441 解决方案 QQ群152889761 加入我们 QQ群649347320 共享学习 QQ群674240731 纪年科技am

额外说明

非技术文—关于英语和如何正确的提问

这篇是杂谈,就关于程序猿英语是否有要求及如何正确提问的问题闲聊几句,希望对大家有所帮助。 一、关于英语 虽然不是必须,不是刚需,但是不得不承认的一点是:英语是优秀程序员必须得跨过去的坎; 而且我想很清楚的说在知识类、非虚构类作品中,英文作品就全世界来说确

额外说明

操作系统知识——PV操作

用自己理解的语言描述,如有错误,请疯狂打脸没关系,希望能够指出来。 0. 几个概念 临界资源:一次只能供一个进程使用的资源。 互斥: 几个进程都需要同时使用同一临界资源。 同步:几个进程在某个任务点协调工作,次序等待。 信号量: 公用:实现互斥,初始值为

额外说明

AI未来十年新范式,生成式人工智能的挑战与机遇

目录 0 写在前面 1 什么是生成式模型? 2 生成式模型的挑战 3 自主智能新架构 4 持续学习与表征解耦 4.1 学习范式 4.2 学习架构 5 生成式AI与元宇宙 6 智慧文档:赋能数字化转型 7 结语 0 写在前面 2023年3月18日,由中国图

额外说明

二叉树的序列化和反序列化

 二叉树的序列化是指把二叉树保存成字符串的形式,而二叉树的反序列化则表示把保存成字符串形式的数据恢复成二叉树。  根据二叉树序列化的定义,二叉树序列化比较简单,用#表示为空,保存时,每个节点用逗号隔开,这样,用前序遍历的形式就可以很容易序列化二叉树。反序

额外说明

Redis实现微博好友功能微服务(关注,取关,共同关注)

文章目录 需求分析 设计思路 数据库表设计 新建好友功能微服务 添加依赖和配置 添加配置类 关注/取关实现 业务逻辑 Mapper实现 Service层实现 Controller实现 网关配置路由规则 测试验证 共同关注列表 Controller添加方法

额外说明

如何创建WooCommerce弹出窗口来增加销售额(6种经过验证的方法)

您想创建 WooCommerce 弹出窗口来促进销售吗? 您想创建 WooCommerce 弹出窗口来增加销售额吗? 灯箱弹出窗口可让您轻松吸引客户的注意力并促使他们进行购买。您可以使用 WooCommerce 弹出窗口提供优惠券、促进销售、吸引访问者进

ads via 小工具