一、SpringMVC
1.1 引言
java开源框架,Spring Framework的一个独立模块。
MVC框架,在项目中开辟MVC层次架构
对控制器中的功能 包装 简化 扩展践行工厂模式,功能架构在工厂之上
1.2 MVC架构
1.2.1 概念
名称职责Model模型:即业务模型,负责完成业务中的数据通信处理,对应项目中的 service和dao
指工程中的javabean,用来处理数据。这个javabean分两类:1.实体类的bean 专门封装数据2.业务处理bean,比如 service 和 dao ,用于处理业务逻辑和数据访问View视图:渲染数据,生成页面。对应项目中的Jsp , html 等 作用是与用户交互 展示数据Controller控制器:直接对接请求,控制MVC流程,调度模型,选择视图。对应项目中的Servlet 接受请求 和 响应数据给浏览器
MVC的工作流程: 用户通过视图层 发送请求到 服务器 ,在服务器中 请求被 Controller 接受,Controller 则调用响应的model层来处理请求,处理完之后的结果 返回给Controller,然后 controller 把结果响应给View 视图,渲染数据 最终展示在浏览器
1.2.2 好处
- MVC是现下软件开发中的最流行的代码结构形态;
- 人们根据负责的不同逻辑,将项目中的代码分成 M V C 3个层次;
- 层次内部职责单一,层次之间耦合度低;
- 符合低耦合 高内聚的设计理念。也实际有利于项目的长期维护。
二、开发流程
2.1 导入依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.9.RELEASE</version></dependency>
2.2 配置核心(前端)控制器
作为一个MVC框架,首先要解决的是:如何能够收到请求!
所以MVC框架大都会设计一款前端控制器,选型在 Servlet 或 Filter两者之一,在框架最前沿率先工作,接收所有请求。
此控制器在接收到请求后,还会负责springMVC的核心的调度管理,所以既是前端又是核心。
补充:DispatcherServlet 前端控制器 ,是框架提供的,作用 统一处理请求和响应,整个流程的控制中心,是由它来调用其他组件处理用户的请求
<servlet><servlet-name>mvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 局部参数:声明配置文件位置 --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:mvc.xml</param-value></init-param><!-- Servlet启动时刻:可选 --><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>mvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
2.3 后端控制器
等价于之前定义的Servlet
@Controller//声明这是一个控制器@RequestMapping("/hello")//访问路径 ,等价于url-patternpublicclassHelloController{@RequestMapping("/test1")//访问路径publicStringhello1(){System.out.println("hello world");return"index";// 跳转:/index.jsp }@RequestMapping("/test2")//访问路径publicStringhello2(){System.out.println("hello c9");return"views/users";// 跳转:/views/user.jsp}}
2.4 配置文件
默认名称:核心控制器名-servet.xml 默认位置:WEB-INF
随意名称:mvc.xml 随意位置:resources 但需要配置在核心控制器中
<beansxmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 告知springmvc 哪些包中 存在 被注解的类 --><context:component-scanbase-package="com.qf.controller"></context:component-scan><!-- 注册注解开发驱动 --><mvc:annotation-driven></mvc:annotation-driven><!-- 视图解析器
作用:1.捕获后端控制器的返回值="index"
2.解析: 在返回值的前后 拼接 ==> "/index.jsp"
--><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><!-- 前缀 --><propertyname="prefix"value="/"></property><!-- 后缀 --><propertyname="suffix"value=".jsp"></property></bean></beans>
2.5 访问
http://localhost:8989/hello/test1
http://localhost:8989/hello/test2
三、接收请求参数
3.1 基本类型参数
请求参数和方法的形参 同名即可
springMVC默认可以识别的日期字符串格式为: YYYY/MM/dd HH:mm:ss
通过@DateTimeFormat可以修改默认日志格式
// id name gender// http://localhost:8989/xxx/../test1?id=1&name=zzz&gender=false&birth=2018-12-12 12:20:30@RequestMapping("/test1")publicStringtestParam1(Integer id,String name,Boolean gender,@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")Date birth){System.out.println("test param1");return"index";}
3.2 实体收参【
重点
】
请求参数和实体的属性 同名即可
publicclassUser{privateInteger id;privateString name;@DateTimeFormat(pattern="yyyy-MM-dd")privateDate birth;privateBoolean gender;//set/get ...}//http://localhost:8989/.../test2?id=1&name=zzz&gender=false&birth=2018-12-12 12:20:30@RequestMapping("/test2")publicStringtestParam2(User user){System.out.println("test param2");System.out.println("user:"+user);return"index";}
3.3 数组收参
简单类型的 数组
<form>
......
<inputtype="checkbox"name="hobby"value="fb"/>足球
<inputtype="checkbox"name="hobby"value="bb"/>篮球
<inputtype="checkbox"name="hobby"value="vb"/>排球
</form>
//http://localhost:8989/.../test3?hobby=football&hobby=basketball@RequestMapping("/test3")publicStringtestParam3(String[] hobby){for(String h:hobby){System.out.print(h+" ");}return"index";}
3.4 集合收参 【了解】
publicclassUserList{//private User[] users;privateList<User> users;//set/get..}// <input type="text" name="users[0].id"/>// post请求:http://...?users[0].id=1&users[0].name=zhangsan&users[0].birth=2018-12-12&users[1].id=2&....@RequestMapping("/test4")publicStringtestParam4(UserList userList){for(User user:userList.getUsers()){System.out.println(user);}return"index";}
3.5 路径参数
// {id} 定义名为id的路径;【/hello/{id}】的匹配能力和【/hello/*】等价// http://localhost:8989/.../hello/10 {id}匹配到10@RequestMapping("/hello/{id}")// @PathVariable将{id}路径匹配到值赋给id参数// 路径名和参数名相同则@PathVariable("id")可简写为 @PathVariablepublicStringtestParam5(@PathVariable("id")Integer id){System.out.println("id:"+id);return"index";}// http://localhost:8989/.../hello/tom {username}匹配到tom@RequestMapping("/hello/{username}")publicStringtestParam6(@PathVariable("username")String name){//将{username}路径匹配到的值赋给name参数System.out.println("username:"+name);return"index";}
3.6 中文乱码
首先,页面中字符集统一
JSP : <%@page pageEncoding="utf-8" %>
HTML : <meta charset="UTF-8">
其次,tomcat中字符集设置,对get请求中,中文参数乱码有效
Tomcat配置:URIEncoding=utf-8
最后,设置此filter,对post请求中,中文参数乱码有效
<!-- 此过滤器会进行:request.setCharactorEncoding("utf-8"); --><filter><filter-name>encoding</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encoding</filter-name><url-pattern>/*</url-pattern></filter-mapping>
个人补充:
@RequestMapping 注解的细节
* @RequestMapping 注解 可以做用在 类 和 方法上面
*
* 将请求 和 处理请求的控制器的方法关联在一起 建立映射关系
* 请求 是如何找到 后端控制器的方法的?
* ip:port/propath/资源路径 资源路径 = 类上面的 RequestMapping的 value / 方法上面的 RequestMapping的 value
*
*
* 关于这个注解 的属性
* value
* 这个属性 用来做 请求映射 他的值 是一个 字符串类型的数组 表式这个请求映射 可以匹配对个地址
* method
*
* 其他属性 遇到再研究
* params
*
* headers
*
* consumers
*
* produces
*
*
*/
四、跳转
4.1 转发
@RequestMapping("/forw")classForwardController{@RequestMapping("/test1")publicStringtestForward(){System.out.println("test forward1");// 转发跳转 /views/users.jsp// return "views/users";//和下一行等价return"forward:/views/users.jsp";}@RequestMapping("/test2")publicStringtestForward2(){System.out.println("test forward2");//转发到 /forw/test1//return "forward:test1";//相对路径(转发到本类中的test1)//转发到 /forw/test1return"forward:/forw/test1";//绝对路径}}
4.2 重定向
@RequestMapping("/redir")classRedirectController{@RequestMapping("/test1")publicStringtestRedirect1(){System.out.println("test redirect1");//重定向到 /redir/test1//return "redirect:test1"; //相对路径(转发到本类中的test1)return"redirect:/redir/test1";//绝对路径}@RequestMapping("/test2")publicStringtestRedirect2(){System.out.println("test redirect2");//重定向到 /views/users.jspreturn"redirect:/view/user.jsp";}}
4.3 跳转细节
- 在增删改之后,为了防止请求重复提交,重定向跳转
- 在查询之后,可以做转发跳转
五、传值
C得到数据后,跳转到V,并向V传递数据。进而V中可以渲染数据,让用户看到含有数据的页面
转发跳转:Request作用域
重定向跳转:Session作用域
5.1 Request和Session
//形参中 即可获得 request 和 session对象@RequestMapping("/test1")publicStringtestData(HttpSession session,HttpServletRequest req,Integer id){
session.setAttribute("user",newUser());
req.setAttribute("age",18);
req.setAttribute("users",Arrays.asList(newUser(),newUser()));//return "test2";return"forward:/WEB-INF/test2.jsp";}
5.2 JSP中取值
建议:重点复习 EL JSTL
//jsp中用EL表达式 取值即可
<fmt:formatDate value="${sessionScope.user.birth}" pattern="yyyy-MM-dd"/> <br/>
${sessionScope.user.birth} <br>
${requestScope.age}
5.3 Model
//model中的数据,会在V渲染之前,将数据复制一份给request@RequestMapping("/test")publicStringtestData(Model model){
model.addAttribute("name","张三");return"index";}//jsp中用EL表达式 取值即可
${requestScope.name}
5.4 ModelAndView
//modelandview 可以集中管理 跳转和数据@RequestMapping("/test")publicModelAndViewtestData(){//返回值类型为ModelAndView//新建ModelAndView对象ModelAndView mv =newModelAndView();// 设置视图名,即如何跳转
mv.setViewName("forward:/index.jsp");// 增加数据
mv.addObject("age",18);return mv;}//jsp中用EL表达式 取值即可
${requestScope.age}
5.5 @SessionAttributes
- @SessionAttributes({“gender”,“name”}) :model中的 name和gender 会存入session中
- SessionStatus 移除session
@Controller@SessionAttributes({"gender","name"})// model中的 name和gender 会存入session中publicclassUserController{@RequestMapping("/hello")publicStringhello(Model m){
m.addAttribute("gender",true);// 会存入session
mv.addObject("name","zhj");// 会存入sessionreturn"index";}@RequestMapping("/hello2")publicStringhello(SessionStatus status){// 移除通过SessionAttributes存入的session
status.setComplete();return"index";}}
六、静态资源
6.1 静态资源问题
静态资源:html,js文件,css文件,图片文件
静态文件没有url-pattern,所以默认是访问不到的,之所以可以访问,是因为,tomcat中有一个全局的servlet:org.apache.catalina.servlets.DefaultServlet,它的url-pattern是 “/”,是全局默认的Servlet. 所以每个项目中不能匹配的静态资源的请求,有这个Servlet来处理即可。
但,在SpringMVC中DispatcherServlet也采用了 “/” 作为url-pattern, 则项目中不会再使用全局的Serlvet,则静态资源不能完成访问。
6.2 解决方案1
DispathcerServlet采用其他的url-pattern
此时,所有访问handler的路径都要以 action结尾!!
<servlet><servlet-name>mvc9</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class></servlet><servlet-mapping><servlet-name>mvc9</servlet-name><url-pattern>*.action</url-pattern></servlet-mapping>
6.3 解决方案2 推荐
DispathcerServlet的url-pattern依然采用 “/”,但追加配置
<!--
额外的增加一个handler,且其requestMapping: "/**" 可以匹配所有请求,但是优先级最低
所以如果其他所有的handler都匹配不上,请求会转向 "/**" ,恰好,这个handler就是处理静态资源的
处理方式:将请求转会到tomcat中名为default的Servlet
--><mvc:default-servlet-handler/>
6.4 解决方案3
- mapping是访问路径,location是静态资源存放的路径
- 将/html/** 中 /**匹配到的内容,拼接到 /hhh/后 http://…/html/a.html 访问 /hhh/a.html
<mvc:resourcesmapping="/html/**"location="/hhh/"/>
七、Json处理
HttpMessageConverter 报文信息转换器 它可以将请求报文转为java对象,或 将 java对象转为响应报文
HttpMessageConverter 提供了
两个注解
@RequestBody 可以获取请求体 需要在控制器的方法形参上使用 使用请求体中的参数 给当前形参赋值 将请求体中的json数据转为java对象
@ResponseBody 作用在 控制器的方法上面 把响应的数据 转为 json
两个类 不常用了解
RequestEntity 写在方法 的 形参上 封装 请求体 请求头信息
ResponseEntity 是方法的返回值
7.1 导入依赖
<!-- Jackson springMVC默认的Json解决方案选择是 Jackson,所以只需要导入jackson的jar,即可使用。--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.8</version></dependency>
7.2 使用@ResponseBody
@ControllerpublicclassJsonController{@RequestMapping("/test1")@ResponseBody//将handler的返回值,转换成json(jackson),并将json响应给客户端。publicUserhello1(){System.out.println("hello world");User user =newUser();return user;}// @ResponseBody还可以用在handler的返回值上@RequestMapping("/test2")public@ResponseBodyList<User>hello2(){System.out.println("hello world");List<User> users =Arrays.asList(newUser(),newUser());return users;}// 如果返回值已经是字符串,则不需要转json,直接将字符串响应给客户端 @RequestMapping(value="/test3",produces ="text/html;charset=utf-8")//produces 防止中文乱码@ResponseBodypublicStringhello2(){System.out.println("hello world");return"你好";}}
7.3 使用@RestController
Controller类上加了@RestController注解,等价于在类中的每个方法上都加了@ResponseBody
@Controller@RestControllerpublicclassJsonController{@RequestMapping("/test1")publicUserhello1(){System.out.println("hello world");User user =newUser();return user;}//@ResponseBody还可以用在handler的返回值上@RequestMapping("/test2")publicList<User>hello2(){System.out.println("hello world");List<User> users =Arrays.asList(newUser(),newUser());return users;}}
7.4 使用@RequestBody
@RequestBody, 接收Json参数
7.4.1 定义Handler
classUser{privateInteger id;privateString name;privateBoolean gender;//set get}
@RequestMapping("/users")publicStringaddUser(@RequestBodyUser user){//@RequestBody将请求体中的json数据转换为java对象System.out.println("cap2");System.out.println("Post user :"+user);return"index";}
7.4.2 Ajax发送json
var xhr =newXMLHttpRequest();
xhr.open("post","${pageContext.request.contextPath}/users?"+newDate().getTime());
xhr.setRequestHeader("content-type","application/json");//设置请求头
xhr.send('{"id":1,"name":"shine","gender":"true"}');//传递json串
//ajaxvar user ={id:1,name:"shine"};
$.ajax({url:'${pageContext.request.contextPath}/json2/test4',type:'post',contentType:"application/json",//声明请求参数类型为 jsondata:JSON.stringify(user),// 转换js对象成jsonsuccess:function(ret){
console.log(ret);}});
记住:
js 对象 转为 json 串 方法: JSON.stringify(user);
json串转为 js 对象的方法 : JSON.parse(jsonstr);
7.5 Jackson常用注解
7.5.1 日期格式化
@JsonFormat(pattern=“yyyy-MM-dd HH:mm:ss”,timezone = “GMT+8”)
publicclassUser{privateInteger id;privateString name;@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone ="GMT+8")privateDate birth;....
get/set
}
7.5.2 属性名修改
@JsonProperty(“new_name”)
publicclassUser{@JsonProperty("new_id")//不再使用原属性名,而是 "new_id"privateInteger id;privateString name;....
get/set
}
输出的json:{“new_id”:xx,"name":"xx"}
7.5.3 属性忽略
@JsonIgnore
publicclassUser{privateInteger id;@JsonIgnore// 生成json时,忽略此属性privateString name;....
get/set
}
输出json时:{"id":xx}
7.5.4 null和empty属性排除
Jackson 默认会输出null值的属性,如果不需要,可以排除。
@JsonInclude(JsonInclude.Include.NON_NULL) //null值 属性不输出
@JsonInclude(value= JsonInclude.Include.NON_EMPTY) // empty属性不输出( 空串,长度为0的集合,null值)
publicclassUser{privateInteger id;@JsonInclude(JsonInclude.Include.NON_NULL)// 若"name==null" 忽略此属性privateString name;@JsonInclude(value=JsonInclude.Include.NON_EMPTY)// 若hobby长度为0或==null 忽略此属性privateList<String> hobby;....
get/set
}
如果name=null,且 hobby长度为0,则输出json时:{"id":xx}
7.5.5 自定义序列化
@JsonSerialize(using = MySerializer.class) // 使用MySerializer输出某属性
publicclassUser{privateInteger id;privateString name;@JsonSerialize(using =MySerializer.class)privateDouble salary =10000.126;//在输出此属性时,使用MySerializer输出....
get/set
}
则输出json时:{"id":xx,"name":"xxx","salary":10000.13}
publicclassMySerializerextendsJsonSerializer<Double>{// value即 Double salary的值@Overridepublicvoidserialize(Double value,JsonGenerator gen,SerializerProvider serializers)throwsIOException{// 将Double salary的值 四舍五入String number =BigDecimal.valueOf(value).setScale(2,BigDecimal.ROUND_HALF_UP).toString();// 输出 四舍五入后的值
gen.writeNumber(number);}}
7.6 FastJson
7.6.1 导入依赖
<!-- FastJson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.54</version></dependency>
7.6.2 安装FastJson
<mvc:annotation-driven><!-- 安装FastJson,转换器 --><mvc:message-converters><beanclass="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"><!-- 声明转换类型:json --><propertyname="supportedMediaTypes"><list><value>application/json</value></list></property></bean></mvc:message-converters></mvc:annotation-driven>
7.6.3 使用
@ResponseBody @RequestBody @RestController 使用方法不变
7.6.4 常用注解
- 日期格式化:@JSONField(format=“yyyy/MM/dd”)
- 属性名修改:@JSONField(name=“birth”)
- 忽略属性:@JSONField(serialize = false)
- 包含null值: - @JSONField(serialzeFeatures = SerializerFeature.WriteMapNullValue) 默认会忽略所有null值,有此注解会输出null- @JSONField(serialzeFeatures = SerializerFeature.WriteNullStringAsEmpty) null的String输出为""
- 自定义序列化:@JSONField(serializeUsing = MySerializer2.class)
publicclassUserimplementsSerializable{@JSONField(serialize =false)privateInteger id;@JSONField(name="NAME",serialzeFeatures =SerializerFeature.WriteNullStringAsEmpty)privateString name;@JSONField(serialzeFeatures =SerializerFeature.WriteMapNullValue)privateString city;@JSONField(format="yyyy/MM/dd")privateDate birth;@JSONField(serializeUsing =MySerializer2.class)privateDouble salary;...}
publicclassMySerializer2implementsObjectSerializer{@Overridepublicvoidwrite(JSONSerializer serializer,Object object,Object fieldName,Type fieldType,int features)throwsIOException{Double value =(Double) object;// salary属性值String text = value +"元";// 在salary后拼接 “元”
serializer.write(text);// 输出拼接后的内容}}
newUser(1,null,null,newDate(),100.5);// 如上对象,转换json:{NAME:"",city:null,"birth":"2020/12/12","salary":"100.5元"}
八、异常解析器
8.1 现有方案,分散处理
Controller中的每个Handler自己处理异常
此种处理方案,异常处理逻辑,分散在各个handler中,不利于集中管理
publicStringxxx(){try{...}catch(Exception1 e){
e.printStackTrace();return"redirect:/xx/error1";}catch(Exception2 e){
e.printStackTrace();return"redirect:/xx/error2";}}
8.2 异常解析器,统一处理
Controller中的每个Handler不再自己处理异常,而是直接throws所有异常。
定义一个“异常解析器” 集中捕获处理 所有异常
此种方案,在集中管理异常方面,更有优势!
8.3 自定义异常
package com.glls.exception;import java.io.Serializable;
public class CustomerException extends Exception implements Serializable {
private static final long serialVersionUID = -5212079010855161498L;
public CustomerException(){}
public CustomerException(String message){
super(message);}}
8.4 自定义异常解析器1
packagecom.glls.exception;importorg.springframework.web.servlet.HandlerExceptionResolver;importorg.springframework.web.servlet.ModelAndView;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;publicclassCustomExceptionResolverimplementsHandlerExceptionResolver{/**
* 异常解析器:主体逻辑
* 执行时刻:当handler中抛出异常时,会执行:捕获异常,并可以跳到错误页面
*/@OverridepublicModelAndViewresolveException(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Object o,Exception e){CustomerException customerException =null;if(e instanceofCustomerException){
customerException =(CustomerException) e;}else{// 如果系统抛出的异常 不是自定义异常 可以重新构造一个未知错误异常
customerException =newCustomerException("未知错误,请联系系统管理员");}ModelAndView modelAndView =newModelAndView();
modelAndView.addObject("error",customerException.getMessage());
modelAndView.setViewName("error");return modelAndView;}}
<!-- 声明异常解析器 --><beanid="handlerExceptionResolver"class="com.glls.exception.CustomExceptionResolver"/>
8.5 自定义异常解析器2
packagecom.qf.java2110.exception;importcom.qf.java2110.common.R;importorg.springframework.http.HttpStatus;importorg.springframework.stereotype.Component;importorg.springframework.web.bind.MissingServletRequestParameterException;importorg.springframework.web.bind.annotation.ControllerAdvice;importorg.springframework.web.bind.annotation.ExceptionHandler;importorg.springframework.web.bind.annotation.ResponseBody;importorg.springframework.web.bind.annotation.ResponseStatus;/**
* @ClassName : CustomExceptionResolver
* @Description : 第二种 全局异常处理器 返回 json 数据
不需要事先接口 借助 @ControllerAdvice 这个注解
*/@Component@ControllerAdvice// 对 controller 进行 增强@ResponseBodypublicclassCustomExceptionResolver2{/**
* 自定义异常
* @param ex CustomException
* @return
*/@ExceptionHandler(CustomerException.class)@ResponseStatus(value =HttpStatus.BAD_REQUEST)publicRhandleHttpMessageNotReadableException(CustomerException ex){returnnewR(444, ex.getMessage());}/**
* 除零异常
* @param ex ArithmeticException
* @return
*/@ExceptionHandler(ArithmeticException.class)@ResponseStatus(value =HttpStatus.BAD_REQUEST)publicRhandleHttpMessageNotReadableException(ArithmeticException ex){returnnewR(444, ex.getMessage());}/**
* 缺少请求参数异常
* @param ex MissingServletRequestParameterException
* @return
*/@ExceptionHandler(MissingServletRequestParameterException.class)@ResponseStatus(value =HttpStatus.BAD_REQUEST)publicRhandleHttpMessageNotReadableException(MissingServletRequestParameterException ex){returnnewR(400,"缺少必要的请求参数");}/**
* 系统异常 预期以外异常
* @param ex
* @return
*
* 项目中,我们一般都会比较详细的去拦截一些常见异常,拦截 Exception 虽然可以一劳永逸,
* 但是不利于我们去排查或者定位问题。实际项目中,可以把拦截 Exception 异常写在 GlobalExceptionHandler
* 最下面,如果都没有找到,最后再拦截一下 Exception 异常,保证输出信息友好。
*/@ExceptionHandler(Exception.class)@ResponseStatus(value =HttpStatus.INTERNAL_SERVER_ERROR)publicRhandleUnexpectedServer(Exception ex){returnnewR(500,"系统发生异常,请联系管理员");}}
九、拦截器
9.1 作用
作用:抽取handler (就是 controller) 中的冗余功能
9.2 定义拦截器
执行顺序: preHandle–postHandle–afterCompletion
publicclassMyInter1implementsHandlerInterceptor{//主要逻辑:在handler之前执行:抽取handler中的冗余代码@OverridepublicbooleanpreHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throwsException{System.out.println("pre~~~");/*
response.sendRedirect("/springMVC_day2/index.jsp");//响应
return false;//中断请求
*/returntrue;//放行,后续的拦截器或handler就会执行}//在handler之后执行:进一步的响应定制@OverridepublicvoidpostHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView)throwsException{System.out.println("post~~");}//在页面渲染完毕之后,执行:资源回收@OverridepublicvoidafterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex)throwsException{System.out.println("after~~");}}
9.3 配置拦截路径
<mvc:interceptors><mvc:interceptor><mvc:mappingpath="/inter/test1"/><mvc:mappingpath="/inter/test2"/><mvc:mappingpath="/inter/test*"/><!-- test开头 --><mvc:mappingpath="/**"/><!-- /** 任意多级任意路径 --><mvc:exclude-mappingpath="/inter/login"/><!--不拦截此路径--><beanclass="com.glls.interceptor.MyInter1"></bean><!--拦截器类--></mvc:interceptor></mvc:interceptors>
拦截器的应用场景 根据其特性 类似于 过滤器 ,比如 可以做 权限校验 日志记录 等等
面试题: 拦截器 于 过滤器的区别?
十、上传与下载
文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。
10.1 文件上传三要素
- 表单的提交方式 method=“POST”
- 表单的enctype属性是多部分表单形式 enctype=“multipart/form-data"
- 表单项(元素)type=“file”
<form action="/upload"enctype="multipart/form-data"method="post">
用户:<input type="text"name="username"><br />
请选择要上传的文件:<input type="file"name="file"/><br /><input type="submit"value="upload"></form>
10.2 enctype 属性值
- application/x-www-form-urlencoded> 默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
- multipart/form-data> 这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
- text/plain> 除了把空格转换为 “+” 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
注意:
一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。
10.3文件上传的方式
- 使用apache提供的工具类 commons-fileupload(麻烦)
- 使用servlet3.0版本,通过注解使用
- 使用SpirngMVC的MultipartResolver
Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类,因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件。
10.4 文件上传操作步骤
10.4.1 导入依赖
<!--文件上传--><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version></dependency><!--servlet 需要这个依赖 并且 tomcat8 版本 要不会有 request 转换异常--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency>
10.4.2 编写表单
<%@ page contentType="text/html;charset=UTF-8"language="java" %><html><head><title>Title</title></head><body><!--单文件上传--><form action="${pageContext.request.contextPath}/upload"enctype="multipart/form-data"method="post">
用户:<input type="text"name="username"><br />
请选择要上传的文件:<input type="file"name="file"/><br /><input type="submit"value="上传"></form></body></html>
10.4.3 配置文件上传组件
<!--文件上传配置--><bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 --><property name="defaultEncoding"value="utf-8"/><!-- 上传文件大小上限,单位为字节(10485760=10M) --><property name="maxUploadSize"value="10485760"/></bean>
10.4.4 编写UploadAndDownloadController
package com.glls.controller;import org.apache.commons.io.FileUtils;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.multipart.MultipartFile;import org.springframework.web.multipart.MultipartHttpServletRequest;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.File;import java.io.IOException;import java.util.Arrays;import java.util.List;import java.util.UUID;
@Controller
public class UploadAndDownloadController {
@RequestMapping("/upload")
public String upload(MultipartFile upload,String name, HttpServletRequest request) throws IOException {
System.out.println(name);
System.out.println(upload);
String filename = upload.getOriginalFilename();
String realPath = request.getServletContext().getRealPath("/");
File uploadDir = new File(realPath,"upload");
if(!uploadDir.exists()){
uploadDir.mkdirs();}
// 底层 是 IO 流操作
upload.transferTo(new File(uploadDir,filename));
request.setAttribute("result","上传成功");
// 得到上传的目录下的 所有文件的名字 放在集合 传到页面以超链接的形式展示 进行下载
String[] list = uploadDir.list();
List<String> fileNames = Arrays.asList(list);
request.setAttribute("fileNames",fileNames);return"result";}}
result.jsp
<%@ page contentType="text/html;charset=UTF-8"language="java" %><%@ taglib prefix="c"uri="http://java.sun.com/jsp/jstl/core" %><html><head><title>Title</title></head><body>${result}<br><c:forEach var="file"items="${fileNames}">${file}<a href="${pageContext.request.contextPath}/upload/download?filename=${file}">下载</a></c:forEach></body></html>
10.4.5 多文件上传
<form action="${pageContext.request.contextPath}/method2"method="post"enctype="multipart/form-data">
用户名: <input type="text"name="name"><br>
文件: <input type="file"name="upload">
文件: <input type="file"name="upload">
文件: <input type="file"name="upload"><br><input type="submit"value="提交"></form>
------------------------------------------------------------------
@RequestMapping("/method2")
public String upload2(MultipartFile[] upload,String name, HttpServletRequest request) throws IOException {
System.out.println(name);
System.out.println(upload);
for(MultipartFile multipartFile:upload){
String filename = multipartFile.getOriginalFilename();
String suffix = filename.substring(filename.lastIndexOf("."));
if(suffix.equalsIgnoreCase(".jpg")){
String uuid = UUID.randomUUID().toString();
multipartFile.transferTo(new File("E://",uuid + suffix));
request.setAttribute("result","上传成功");}else{
request.setAttribute("result","上传失败");}}return"result";}
10.5 文件下载
@RequestMapping("/download")
public void download(String filename, HttpServletResponse response,HttpServletRequest request) throws IOException {
// 设置响应头告诉浏览器以何种方式处理响应
response.setHeader("content-disposition","attachment;filename="+filename);
System.out.println(filename);
ServletOutputStream outputStream = response.getOutputStream();
String path = request.getServletContext().getRealPath("/upload");
File file= new File(path, filename);
byte[] bytes = FileUtils.readFileToByteArray(file);
outputStream.write(bytes);
outputStream.close();}
十一、验证码
11.1 作用
防止暴力攻击,前端安全保障
11.2 导入jar
<!-- Kaptcha --><dependency><groupId>com.github.penggle</groupId><artifactId>kaptcha</artifactId><version>2.3.2</version><exclusions><exclusion><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId></exclusion></exclusions></dependency>
11.3 声明验证码组件
<servlet><servlet-name>cap</servlet-name><servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class><init-param><param-name>kaptcha.border</param-name><param-value>no</param-value></init-param><init-param><param-name>kaptcha.textproducer.char.length</param-name><param-value>4</param-value></init-param><init-param><param-name>kaptcha.textproducer.char.string</param-name><param-value>abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</param-value></init-param><init-param><param-name>kaptcha.background.clear.to</param-name><param-value>211,229,237</param-value></init-param><init-param><!-- session.setAttribute("captcha","验证码") --><param-name>kaptcha.session.key</param-name><param-value>captcha</param-value></init-param></servlet><servlet-mapping><servlet-name>cap</servlet-name><url-pattern>/captcha</url-pattern></servlet-mapping>
11.4 Page
<imgsrc="${pageContext.request.contextPath}/captcha"style="width:85px"id="cap"/><script>$(function(){$("#cap").click(function(){//刷新验证码
path =$(this).attr("src")+"?"+newDate().getTime();$(this).attr("src",path);});});</script>
十二、REST
12.1 开发风格
是一种开发风格,遵从此风格开发软件,符合REST风格,则RESTFUL。
两个核心要求:
- 每个资源都有唯一的标识(URL)
- 不同的行为,使用对应的http-method
12.2 优点
- **输出json:
12.3 使用
12.3.1 定义Rest风格的 Controller
@RequestMapping(value=“/users”,method = RequestMethod.GET)
等价
@GetMapping(“/users”)
@RestControllerpublicclassRestController{@GetMapping("/users")publicList<User>queryAllUsers(){System.out.println("get");List<User> users =....return users;}@PostMapping("/users")publicStringaddUser(@RequestBodyUser user){System.out.println("Post user :"+user);return"{status:1}";}@PutMapping("/users")publicStringupdateUser(@RequestBodyUser user){System.out.println("Put user" user:"+user);return"{status:1}";}@GetMapping("/users/{id}")publicStringqueryOneUser(@PathVariableInteger id){//@PathVariable 接收路径中的值System.out.println("Get user id:"+id);return"{status:1}";}@DeleteMapping("/users/{id}")publicStringdeleteOneUser(@PathVariableInteger id){//@PathVariable 接收路径中的值System.out.println("delete user id:"+id);return"{status:1}";}}
12.3.2 Ajax请求
<script>functionputUser(){// 发送更新请求 (增加请求发送方式也是如此)var xhr =newXMLHttpRequest();//定义 put,delete,get,post方式 即可,不用定义_method
xhr.open("put","${pageContext.request.contextPath}/rest04/users");// 设置请求头
xhr.setRequestHeader("content-type","application/json");
// 设置请求参数var user ={id:1,NAME:"shine",city:"bj","birth":"2020/12/12","salary":100.5};
xhr.send(JSON.stringify(user));
xhr.onreadystatechange=function(){if(xhr.readyState==4&& xhr.status==200){var ret = xhr.responseText;// 解析json,并输出
console.log(JSON.parse(ret));}}/*$.ajax({
url:'${pageContext.request.contextPath}/rest04/users',
type:'put',
contentType:"application/json",//声明请求参数类型为 json
data:JSON.stringify(user),// 转换js对象成json
success:function(ret){
console.log(JSON.parse(ret));
}
});*/}functiondelUser(){// 发送删除请求var xhr =newXMLHttpRequest();//定义 put,delete,get,post方式 即可,不用定义_method
xhr.open("delete","${pageContext.request.contextPath}/rest04/users/1");
xhr.send();
xhr.onreadystatechange=function(){if(xhr.readyState==4&& xhr.status==200){var ret = xhr.responseText;
console.log(JSON.parse(ret));}}}</script>
十三、跨域请求
13.1 域
域:协议+IP+端口
13.2 Ajax跨域问题
- Ajax发送请求时,不允许跨域,以防用户信息泄露。
- 当Ajax跨域请求时,响应会被浏览器拦截(同源策略),并报错。即浏览器默认不允许ajax跨域得到响应内容。
- 互相信任的域之间如果需要ajax访问,(比如前后端分离项目中,前端项目和后端项目之间),则需要额外的设置才可正常请求。
13.3 解决方案
- 允许其他域访问
- 在被访问方的Controller类上,添加注解
@CrossOrigin("http://localhost:8080")//允许此域发请求访问publicclassSysUserController{....}
- 携带对方cookie,使得session可用
- 在访问方,ajax中添加属性:withCredentials: true
$.ajax({type:"POST",url:"http://localhost:8989/web/sys/login",...,xhrFields:{// 跨域携带cookiewithCredentials:true}});
或
var xhr =newXMLHttpRequest();// 跨域携带cookie
xhr.withCredentials=true;
十四、SpringMVC执行流程
DispatcherServlet : 前端控制器 不需要程序员开发 由springmvc框架提供的,它的作用是 统一处理请求和响应 整个流程的控制中心 ,由他来调度其他组件 处理用户的请求
HandlerMapping: 处理器映射器 不需要程序员开发 有框架提供, 它的作用是根据 url ,method 等 信息 查找 handler 准确点说是 controller中的方法
Handler : 需要程序员开发的 controller
HandlerAdapter: 处理器适配器 不需要程序员开发 对handler 方法 进行 调用
ViewResolver: 视图解析器 不需要程序员开发 进行视图解析
View: 视图
Model: 数据
面试题: springmvc 的 核心组件有哪些? 或者 springmvc 的 执行流程是什么?
十五、Spring整合
15.1 整合思路
此时项目中有两个工厂
- DispatcherServlet 启动的springMVC工厂==负责生产C及springMVC自己的系统组件
- ContextLoaderListener 启动的spring工厂==负责生产其他所有组件
- springMVC的工厂会被设置为spring工厂的子工厂,可以随意获取spring工厂中的组件
- 整合过程,就是累加:代码+依赖+配置。然后将service注入给controller即可
15.2 整合技巧
两个工厂不能有彼此侵入,即,生产的组件不能有重合。
<!-- 告知SpringMVC 哪些包中 存在 被注解的类
use-default-filters=true 凡是被 @Controller @Service @Repository注解的类,都会被扫描
use-default-filters=false 默认不扫描包内的任何类, 只扫描include-filter中指定的类
只扫描被@Controller注解的类
--><context:component-scanbase-package="com.zhj"use-default-filters="false"><context:include-filtertype="annotation"expression="org.springframework.stereotype.Controller"/></context:component-scan>
<!-- 告知Spring
唯独不扫描@Controller注解的类 --><context:component-scanbase-package="com.zhj"use-default-filters="true"><context:exclude-filtertype="annotation"expression="org.springframework.stereotype.Controller"/></context:component-scan>
15.3 ssm 整合
1.准备 数据库 ssm 准备表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dGyAJWw7-1682836813650)(E:\gitee\myrepo\my\springmvc\Pictures\image-20201102215248571.png)]
2.创建 maven 的 web 工程 ssm
3.添加依赖
<?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>com.qf.java2110</groupId><artifactId>ssm</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><name>ssm Maven Webapp</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-test --><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.0.RELEASE</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.0.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.0.RELEASE</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.15</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.6</version></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!--分页插件--><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.10</version></dependency><!-- mybatis整合 spring --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.2</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.0.RELEASE</version></dependency><!--springmvc的依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.0.RELEASE</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.20</version></dependency><!--文件上传--><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version></dependency><!--servlet 需要这个依赖 并且 tomcat8 版本 要不会有 request 转换异常--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jsp-api</artifactId><version>2.0</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.10.0</version></dependency><!--logback 日志--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.25</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.2.3</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><dependency><groupId>org.logback-extensions</groupId><artifactId>logback-ext-spring</artifactId><version>0.1.4</version></dependency></dependencies><build><finalName>ssm</finalName><resources><!--在pom.xml文件中加上配置,让编译器把src/main/java目录下的xml文件一同编译到classes文件夹下--><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><resource><directory>src/main/resources</directory><includes><include>**/*.xml</include><include>**/*.properties</include></includes></resource></resources></build></project>
4.web.xml 配置文件
<?xml version="1.0"encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!-- 上下文参数 --><context-param><param-name>contextConfigLocation</param-name><!-- spring 配置文件 --><param-value>classpath:applicationContext.xml</param-value></context-param><!-- 封装了一个监听器,帮助加载 Spring 的配置文件 --><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--配置springmvc的前端控制器--><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:springmvc.xml</param-value>--><param-value>classpath:springmvc.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><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app>
配置文件
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd"><!--基于注解的形式 管理 bean--><!--扫描 com.qf 下的全部组件--><context:component-scanbase-package="com.qf.java2110"use-default-filters="true"><context:exclude-filtertype="annotation"expression="org.springframework.stereotype.Controller"/></context:component-scan><!--掌握 基于 AspectJ 的 注解 的 AOP实现 配置--><aop:aspectj-autoproxy></aop:aspectj-autoproxy><!--配置文件参数化(参数占位符)--><context:property-placeholderlocation="classpath:db.properties"/><!--与DruidDataSource集成(二选一)--><beanid="dataSource"class="com.alibaba.druid.pool.DruidDataSource"init-method="init"destroy-method="close"><!--基本配置--><!--基本配置--><propertyname="driverClassName"value="${jdbc.driver}"/><propertyname="url"value="${jdbc.url}"/><propertyname="username"value="${jdbc.username}"/><propertyname="password"value="${jdbc.password}"/><!-- 配置获取连接等待超时的时间 --><propertyname="maxWait"value="60000"/><!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --><propertyname="timeBetweenEvictionRunsMillis"value="60000"/><!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --><propertyname="minEvictableIdleTimeMillis"value="300000"/></bean><!-- 工厂bean:生成SqlSessionFactory --><beanid="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean"><!--数据源属性--><propertyname="dataSource"ref="dataSource"></property><!--mybatis的配置文件--><propertyname="configLocation"value="classpath:mybatis-config.xml"></property></bean><beanclass="org.mybatis.spring.mapper.MapperScannerConfigurer"><!--扫描mapper 接口 自动创建mapper层代理对象 交给spring管理--><propertyname="basePackage"value="com.qf.java2110.mapper"></property><propertyname="sqlSessionFactoryBeanName"value="sqlSessionFactory"></property></bean><!--整合事务 第一步 配置事务管理器--><beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><propertyname="dataSource"ref="dataSource"></property></bean><!--2.基于注解的形式 开启事务的注解--><tx:annotation-driventransaction-manager="transactionManager"></tx:annotation-driven></beans>
springmvc.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 告知springmvc 哪些包中 存在 被注解的类 --><context:component-scan base-package="com.qf.java2110" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan><!-- 注册注解开发驱动 --><mvc:annotation-driven></mvc:annotation-driven><!-- 视图解析器
作用:1.捕获后端控制器的返回值="index"2.解析: 在返回值的前后 拼接 ==>"/index.jsp"--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!-- 前缀 --><property name="prefix" value="/"></property><!-- 后缀 --><property name="suffix" value=".jsp"></property></bean><!--
额外的增加一个handler,且其requestMapping:"/**" 可以匹配所有请求,但是优先级最低
所以如果其他所有的handler都匹配不上,请求会转向 "/**",恰好,这个handler就是处理静态资源的
处理方式:将请求转会到tomcat中名为default的Servlet--><mvc:default-servlet-handler/><!--<mvc:resources mapping="/image/**" location="/image/"/>--><!--<mvc:interceptors>--><!--<mvc:interceptor>--><!--<mvc:mapping path="/inter/test1"/>--><!--<bean class="com.qf.java2110.interceptor.MyInter1"></bean>--><!--</mvc:interceptor>--><!--<!–<mvc:interceptor>–>--><!--<!–<mvc:mapping path="/**"/><!–/** 任意多级任意路径 –>–>-->
<!--<!– <mvc:exclude-mapping path="/inter/login"/> <!–不拦截此路径–>–>-->
<!--<!– <mvc:exclude-mapping path="/json/test7"/> <!–不拦截此路径–>–>-->
<!--<!– <bean class="com.qf.java2110.interceptor.LoginInterceptor"></bean>–>-->
<!--<!– </mvc:interceptor>–>-->
<!-- </mvc:interceptors>-->
<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
<property name="defaultEncoding" value="utf-8"/>
<!-- 上传文件大小上限,单位为字节(10485760=10M) -->
<property name="maxUploadSize" value="10485760"/>
</bean>
</beans>
db.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
jdbc.username=root
jdbc.password=123456
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPEconfigurationPUBLIC"-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><typeAliases><!--自动扫描包,将原类名作为别名--><packagename="com.qf.java2110.pojo"/></typeAliases><plugins><plugininterceptor="com.github.pagehelper.PageInterceptor"></plugin></plugins><mappers><!--扫描xml 映射文件--><packagename="com.qf.java2110.mapper"/></mappers></configuration>
logback.xml
<?xml version="1.0" encoding="UTF-8"?><configuration><appendername="stdout"class="ch.qos.logback.core.ConsoleAppender"><Target>System.out</Target><Encoding>UTF-8</Encoding><encoder><pattern>%d{yyyy-MM-dd_HH:mm:ss.SSS} %5p [%t] [%c{1}]:%L - %m%n
</pattern></encoder></appender><appendername="logfile"class="ch.qos.logback.core.rolling.RollingFileAppender"><Encoding>UTF-8</Encoding><encoder><pattern>%d %p [%t] [%c]:%L - %m%n</pattern></encoder><filterclass="ch.qos.logback.classic.filter.ThresholdFilter"><level>DEBUG</level></filter><rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>log/%d{yyyy-MM-dd-HH'.log'}</fileNamePattern></rollingPolicy></appender><loggername="org.springframework"level="WARN"/><loggername="org.springframework.remoting"level="WARN"/><loggername="org.springframework.scheduling.quartz"level="WARN"/><loggername="org.springframework.data.jpa"level="DEBUG"/><loggername="org.cometd"level="WARN"/><loggername="ch.qos.logback"level="WARN"/><loggername="com.springapp.mvc"level="DEBUG"/><loggername="com.qf.mapper"level="DEBUG"></logger><!-- <logger name="com.ibatis" level="DEBUG"></logger> --><rootlevel="ERROR"><appender-refref="stdout"/><appender-refref="logfile"/></root></configuration>
~~~xml
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPEconfigurationPUBLIC"-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><typeAliases><!--自动扫描包,将原类名作为别名--><packagename="com.qf.java2110.pojo"/></typeAliases><plugins><plugininterceptor="com.github.pagehelper.PageInterceptor"></plugin></plugins><mappers><!--扫描xml 映射文件--><packagename="com.qf.java2110.mapper"/></mappers></configuration>
logback.xml
<?xml version="1.0" encoding="UTF-8"?><configuration><appendername="stdout"class="ch.qos.logback.core.ConsoleAppender"><Target>System.out</Target><Encoding>UTF-8</Encoding><encoder><pattern>%d{yyyy-MM-dd_HH:mm:ss.SSS} %5p [%t] [%c{1}]:%L - %m%n
</pattern></encoder></appender><appendername="logfile"class="ch.qos.logback.core.rolling.RollingFileAppender"><Encoding>UTF-8</Encoding><encoder><pattern>%d %p [%t] [%c]:%L - %m%n</pattern></encoder><filterclass="ch.qos.logback.classic.filter.ThresholdFilter"><level>DEBUG</level></filter><rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>log/%d{yyyy-MM-dd-HH'.log'}</fileNamePattern></rollingPolicy></appender><loggername="org.springframework"level="WARN"/><loggername="org.springframework.remoting"level="WARN"/><loggername="org.springframework.scheduling.quartz"level="WARN"/><loggername="org.springframework.data.jpa"level="DEBUG"/><loggername="org.cometd"level="WARN"/><loggername="ch.qos.logback"level="WARN"/><loggername="com.springapp.mvc"level="DEBUG"/><loggername="com.qf.mapper"level="DEBUG"></logger><!-- <logger name="com.ibatis" level="DEBUG"></logger> --><rootlevel="ERROR"><appender-refref="stdout"/><appender-refref="logfile"/></root></configuration>
版权归原作者 IT萌新@ 所有, 如有侵权,请联系我们删除。