<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.19.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>5.2.19.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.2.19.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.19.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.19.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>5.2.19.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.2.19.RELEASEversion>
dependency>
<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>
beans>
<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>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-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
的
为/
表示DispatcherServlet会拦截除jsp
的所有资源并解析(/*
表示拦截所有资源),静态资源经过其解析后就不是所需要的了,因此静态资源不需要其解析。
方法一:更改拦映射路径
将DispatcherServlet
的
的路径映射为*.form
或者*.do
就不会再拦截静态资源了。
方法二:服务器默认Servlet(defaultServlet)处理静态资源
将.html,.css,.js,.png,.jpg
等资源交由服务器默认的sevlet处理,如web.xml
的·注释一:
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.htmlurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.cssurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.jsurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.gifurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.pngurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.jpgurl-pattern>
servlet-mapping>
使用该方法不能再引入javax.servlet-api
的jar
工具包了,会起冲突,造成DispatcherServlet
处理异常。
方法三:DispatcherServlet实现对静态资源的放行
<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和classpath这两个参数,其表示的意义:
file: xxx-xxx.xml
在根目录下的配置文件。
classpath:xxx-xxx.xml
在resources
目录下的配置文件。
后端接口主要是由控制器来完成的,控制器包含众多解析器,如上述的DispatcherServlet
执行流程一样,众多解析器分工合作共同完成。
定义一个控制器才能对请求进行解析,一个控制器就必须包含上图的每个部分,有的需要声明,有的自主创建。
@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
若不指定 method 属性,则无论是 GET 还是 POST 提交方式,均可匹配 即对于请求的提交方式无要求。
headers 属性
: 指定request中必须包含某些指定的header值,才能让该方法处理请求。
params属性
:指定request中必须包含某些参数值时,才让该方法处理。
consumes属性
: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
produces属性
: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回。
@ResponseBody控制器指定解析数据的注解。
表单参数
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.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.12.6version>
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]
@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.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.12.6version>
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;
}
此时如果在传错参数类型就会有以下错误提示
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;
}
<bean id="fastJsonHttpMessageConverter"
class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8value>
<value>application/json;charset=UTF-8value>
list>
property>
bean>
除了上面请求携带的参数外控制器还有默认参数。
这些默认参数和servlet的用法一样。
以下配置是配置spring mvc的编码格式:
web.xml
配置
<filter>
<filter-name>characterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
<init-param>
<param-name>forceRequestEncodingparam-name>
<param-value>trueparam-value>
init-param>
<init-param>
<param-name>forceResponseEncodingparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>characterEncodingFilterfilter-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>Titletitle>
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 完成。而转换器的开启,需要由
来完成。转换器依赖Jackson工具包。需要导入依赖:
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.12.6version>
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(maxAge=3600)
@Controller
public class CrossoriginController
{
...
}
表示CrossOriginController
控制器的所有方法可以处理http://www.fkit.org
域上的请求:
@CrossOrigin(
origins="http://www.fkit.org",
maxAge=3600
)
@Controller
public class CrossOriginController
{
....
}
注解用于将请求的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);
}
}
注解用于访问由请求处理方法、过滤器或拦截器创建的、预先存在于request作用域中的属性,并将该request作用域中的属性的值设置到请求处理方法的形式参数上。
@RequestMapping(value="/arrtibuteTest")
public void arrtibuteTest(
@RequestAttribute(value="username") String username){ ... }
以上代码会自动将request作用域中名为username的属性的值设置到username参数上。
注解用将session作用域中的属性赋值给目标方法的形式参数,这些属性由请求处理方法、过滤器或拦截器创建并存在于session作用域中。
@RequestMapping(value="/arrtibuteTest")
public void arrtibuteTest(
@SessionAttribute(value="username") String username) {...}
以上代码会自动将session作用域中名为username的属性的值设置到请求处理方法的username形式参数上。
注解允许我们有选择地指定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
块。
<error-page>
<error-code>404error-code>
<location>/error.htmllocation>
error-page>
<error-page>
<error-code>500error-code>
<location>/base.htmllocation>
error-page>
这种方法过于笼统不利于处理多类型的错误。
<error-page>
<exception-type>Exceptionexception-type>
<location>/error.htmllocation>
error-page>
这种对Java异常的处理,需要熟悉各种异常的类,也不便于处理。
SimpleMappingExceptionResolver
。
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"
p:defaultErrorView="error" p:exceptionAttribute="ex">
<property name="exceptionMappings">
<props>
<prop key="IOException">ioerrorprop>
<prop key="SQLException">sqlerrorprop>
props>
property>
bean>
重点是异常处理的配置。 SimpleMappingExceptionResolver是Spring提供的处理异常的类,所有抛岀的异常都会被该类捕获。
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注解,也就是说可以使用
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注解来修饰,
// 其会被扫描,
// 这使得该类中使用@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
注解来修饰,则该类会被
扫描,该类中使@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=来完成具体的上传操作。使用 CommonsMultipartResolver
来完成文件上传,分为单文件上传和多文件上传两部分介绍:
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.4version>
dependency>
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.2.2version>
dependency>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5000000" />
<property name="defaultEncoding" value="UTF-8" />
bean>
resolveLazily:延迟解析,默认为false--立即解析multipart request;
defaultEncoding:解析请求的默认字符编码 ; 默认值为"ISO-8859-1"。通常设置为"UTF-8";
maxUploadSize:文件上传最大值; 默认值为 -1(表示没有限制);
maxUploadSizePerFile:每个文件上传最大值;默认值为 -1(表示没有限制);
maxInMemorySize:存储在内存的最大值;默认值为10240B(10KB);
uploadTempDir:上传文件的临时目录;默认值为WEB应用程序的临时目录;
servletContext:the servletContext to use;
表单的文件上传需要使用 enctype 属性,并将它的值设置为 multipart/form-data,同时将表单的提交方式设置为 post。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
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>
在该 POJO 类中声明一个 MultipartFile
即(前端的uplaodaFile
)类型的属性封装被上传的文件信息,属性名与前端页面 的
name
属性的相同,代码如下:
import org.springframework.web.multipart.MultipartFile;
public class File {
private String description;
private MultipartFile fileInfo;
}
//测试是否可以传递到后端
@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>Titletitle>
<script src="../js/axios.min.js">script>
head>
<body>
<h1>bookShowh1>
<button type="button" id="btn3" >set headerbutton>
<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框架对数据解析
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<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="";
//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容器中存在拦截器,它们有很大差异:
在Servlet开发中,每个请求对应一个Servlet,因此可以通过Filter管理;但在Spring MVC中,只有一个DispatcherServlet,通过映射来访问Filter不再满足需求,需要通过Ierceptor(拦截器来实现)。
在 Spring MVC 框架中定义一个拦截器需要对拦截器进行定义和配置,主要有以下 2 种方式。
HandlerInterceptor
接口或继承 HandlerInterceptor
接口的实现类(例如//首先是实现接口
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";
}
<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="" />
<bean class="net.biancheng.interceptor.Interceptor1" />
mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/gotoTest" />
<bean class="net.biancheng.interceptor.Interceptor2" />
mvc:interceptor>
mvc:interceptors>
WebRequestInterceptor
接口或继承WebRequestInterceptor
接口的实现类来定义。WebRequestInterceptor和HandlerInterceptor接口中定义的方法作用也是一样的。不同点是
WebRequestInterceptor的入参WebRequest是包装了HttpServletRequest 和HttpServletResponse的,通过WebRequest获取Request中的信息更简便。其次preHandle是没有返回值的,说明该方法中的逻辑并不影响后续的方法执行,所以这个接口实现就是为了获取Request中的信息,或者预设一些参数供后续流程使用。
添加war
的打包依赖,导入servlet和jsp依赖:
<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.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>ssmartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
dependency>
dependencies>
project>
添加持久层框架时不要忘了对应的数据库驱动工具包。
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.11version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.5version>
dependency>
文件不需要任何配置,在IoC容器中通过MapperScannerConfigurer
对象配置
<configuration>
configuration>
Spring MVC整合Mybatis依赖于Ioc容器,像DataSource,SqlSessionFactory,SqlSession,Mapper等对象都可以交给IoC容器管理。同时Spring AOP提供了声明式事务管理,更加方便。
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.1.19.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.1.19.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.1.19.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.1.19.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>5.1.19.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.1.19.RELEASEversion>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.12.3version>
dependency>
如果所有配置文件都集中在一个xml中会过于冗余,使用多配置文件分开管理(并不是独立的分工合作):
beans.xml
配置注解声明,以及bean管理。
<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相关配置,如静态资源,拦截器,视图解析器,异常处理等。
<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:annotation-driven>mvc:annotation-driven>
beans>
mybatis-config.xml
进行Mybatis的配置。
<configuration>
configuration>
spring-mybatis.xml
进行spring于mybatis整合配置。
<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的控制器。
<web-app>
<display-name>Archetype Created Web Applicationdisplay-name>
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring-*.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
在web.xml中配置contextConfigLocation
对象并配置路径,就会加载配置文件并启动IoC容器,不需要再java代码中通过ClassPathApplicationContext
等上下文对象再次加载。
上面的配置实现了spring配置文件到控制器的整合,接下来实现spring于mybatis的整合。
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>1.3.1version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.6version>
dependency>
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
<context:property-placeholder location="classpath:druid.properties">context:property-placeholder>
<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>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="druidDataResource">property>
<property name="mapperLocations" value="classpath:mapper/*.xml">property>
<property name="typeAliasesPackage" value="cms.ssm.model">property>
bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory">property>
<property name="basePackage" value="cms.ssm.dao">property>
bean>
第一个bean实现注入xml文件并创建SqlSessionFactory
,第二个bean负责生产basePackage包下的所有Mapper类并注入sql语句,返回SqlSession
的getMapper()
等方法返回的Mapper类。
<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
<mapper namespace="cms.ssm.dao.UserMapper">
<select id="allUser" resultType="User">
select *
from user
select>
mapper>
dao
中创建UserMapper.java的映射接口public interface UserMapper {
List<User> allUser();
}
在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%2B8
GMT%2B8表示时区东八区
开始也是这个问题看了这个博客的解析,更改后就没问题了。初始化数据库错误,init datasource error, url: jdbc:mysql://localhost:3306/
需要注意的是测试类中需要使用注解加载spring及spring mvc相关文件,当配置了Tomcat后配置文件在web.xml中就加载了,由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环境。