赞
踩
java开源框架,Spring Framework的一个独立模块。
MVC框架,在项目中开辟MVC层次架构
对控制器中的功能 包装 简化 扩展践行工厂模式,功能架构在工厂之上
名称 | 职责 |
---|---|
Model | 模型:即业务模型,负责完成业务中的数据通信处理,对应项目中的 service和dao 指工程中的javabean,用来处理数据。这个javabean分两类:1.实体类的bean 专门封装数据2.业务处理bean,比如 service 和 dao ,用于处理业务逻辑和数据访问 |
View | 视图:渲染数据,生成页面。对应项目中的Jsp , html 等 作用是与用户交互 展示数据 |
Controller | 控制器:直接对接请求,控制MVC流程,调度模型,选择视图。对应项目中的Servlet 接受请求 和 响应数据给浏览器 |
MVC的工作流程: 用户通过视图层 发送请求到 服务器 ,在服务器中 请求被 Controller 接受,Controller 则调用响应的model层来处理请求,处理完之后的结果 返回给Controller,然后 controller 把结果响应给View 视图,渲染数据 最终展示在浏览器
MVC是现下软件开发中的最流行的代码结构形态;
人们根据负责的不同逻辑,将项目中的代码分成 M V C 3个层次;
层次内部职责单一,层次之间耦合度低;
符合低耦合 高内聚的设计理念。也实际有利于项目的长期维护。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
作为一个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>
等价于之前定义的Servlet
@Controller //声明这是一个控制器
@RequestMapping("/hello") //访问路径 ,等价于url-pattern
public class HelloController {
@RequestMapping("/test1") //访问路径
public String hello1(){
System.out.println("hello world");
return "index"; // 跳转:/index.jsp
}
@RequestMapping("/test2") //访问路径
public String hello2(){
System.out.println("hello c9");
return "views/users";// 跳转:/views/user.jsp
}
}
默认名称:核心控制器名-servet.xml 默认位置:WEB-INF
随意名称:mvc.xml 随意位置:resources 但需要配置在核心控制器中
<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.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> </beans>
http://localhost:8989/hello/test1
http://localhost:8989/hello/test2
请求参数和方法的形参 同名即可
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")
public String testParam1(Integer id,
String name,
Boolean gender,
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")Date birth){
System.out.println("test param1");
return "index";
}
重点
】请求参数和实体的属性 同名即可
public class User { private Integer id; private String name; @DateTimeFormat(pattern="yyyy-MM-dd") private Date birth; private Boolean gender; //set/get ... } //http://localhost:8989/.../test2?id=1&name=zzz&gender=false&birth=2018-12-12 12:20:30 @RequestMapping("/test2") public String testParam2(User user){ System.out.println("test param2"); System.out.println("user:"+user); return "index"; }
简单类型的 数组
<form>
......
<input type="checkbox" name="hobby" value="fb"/>足球
<input type="checkbox" name="hobby" value="bb"/>篮球
<input type="checkbox" name="hobby" value="vb"/>排球
</form>
//http://localhost:8989/.../test3?hobby=football&hobby=basketball
@RequestMapping("/test3")
public String testParam3(String[] hobby){
for(String h:hobby){
System.out.print(h+" ");
}
return "index";
}
public class UserList {
//private User[] users;
private List<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")
public String testParam4(UserList userList){
for(User user:userList.getUsers()){
System.out.println(user);
}
return "index";
}
// {id} 定义名为id的路径;【/hello/{id}】的匹配能力和【/hello/*】等价 // http://localhost:8989/.../hello/10 {id}匹配到10 @RequestMapping("/hello/{id}") // @PathVariable将{id}路径匹配到值赋给id参数 // 路径名和参数名相同则@PathVariable("id")可简写为 @PathVariable public String testParam5(@PathVariable("id") Integer id){ System.out.println("id:"+id); return "index"; } // http://localhost:8989/.../hello/tom {username}匹配到tom @RequestMapping("/hello/{username}") public String testParam6(@PathVariable("username") String name){//将{username}路径匹配到的值赋给name参数 System.out.println("username:"+name); return "index"; }
首先,页面中字符集统一
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 * * */
@RequestMapping("/forw") class ForwardController{ @RequestMapping("/test1") public String testForward(){ System.out.println("test forward1"); // 转发跳转 /views/users.jsp // return "views/users";//和下一行等价 return "forward:/views/users.jsp"; } @RequestMapping("/test2") public String testForward2(){ System.out.println("test forward2"); //转发到 /forw/test1 //return "forward:test1";//相对路径(转发到本类中的test1) //转发到 /forw/test1 return "forward:/forw/test1"; //绝对路径 } }
@RequestMapping("/redir") class RedirectController{ @RequestMapping("/test1") public String testRedirect1(){ System.out.println("test redirect1"); //重定向到 /redir/test1 //return "redirect:test1"; //相对路径(转发到本类中的test1) return "redirect:/redir/test1";//绝对路径 } @RequestMapping("/test2") public String testRedirect2(){ System.out.println("test redirect2"); //重定向到 /views/users.jsp return "redirect:/view/user.jsp"; } }
在增删改之后,为了防止请求重复提交,重定向跳转
在查询之后,可以做转发跳转
C得到数据后,跳转到V,并向V传递数据。进而V中可以渲染数据,让用户看到含有数据的页面
转发跳转:Request作用域
重定向跳转:Session作用域
//形参中 即可获得 request 和 session对象
@RequestMapping("/test1")
public String testData(HttpSession session,HttpServletRequest req,Integer id){
session.setAttribute("user",new User());
req.setAttribute("age", 18);
req.setAttribute("users",Arrays.asList(new User(),new User()));
//return "test2";
return "forward:/WEB-INF/test2.jsp";
}
建议:重点复习 EL JSTL
//jsp中用EL表达式 取值即可
<fmt:formatDate value="${sessionScope.user.birth}" pattern="yyyy-MM-dd"/> <br/>
${sessionScope.user.birth} <br>
${requestScope.age}
//model中的数据,会在V渲染之前,将数据复制一份给request
@RequestMapping("/test")
public String testData(Model model){
model.addAttribute("name", "张三");
return "index";
}
//jsp中用EL表达式 取值即可
${requestScope.name}
//modelandview 可以集中管理 跳转和数据
@RequestMapping("/test")
public ModelAndView testData(){//返回值类型为ModelAndView
//新建ModelAndView对象
ModelAndView mv = new ModelAndView();
// 设置视图名,即如何跳转
mv.setViewName("forward:/index.jsp");
// 增加数据
mv.addObject("age",18);
return mv;
}
//jsp中用EL表达式 取值即可
${requestScope.age}
@SessionAttributes({“gender”,“name”}) :model中的 name和gender 会存入session中
SessionStatus 移除session
@Controller @SessionAttributes({"gender","name"}) // model中的 name和gender 会存入session中 public class UserController { @RequestMapping("/hello") public String hello(Model m){ m.addAttribute("gender",true); // 会存入session mv.addObject("name","zhj"); // 会存入session return "index"; } @RequestMapping("/hello2") public String hello(SessionStatus status){ // 移除通过SessionAttributes存入的session status.setComplete(); return "index"; } }
静态资源:html,js文件,css文件,图片文件
静态文件没有url-pattern,所以默认是访问不到的,之所以可以访问,是因为,tomcat中有一个全局的servlet:org.apache.catalina.servlets.DefaultServlet,它的url-pattern是 “/”,是全局默认的Servlet. 所以每个项目中不能匹配的静态资源的请求,有这个Servlet来处理即可。
但,在SpringMVC中DispatcherServlet也采用了 “/” 作为url-pattern, 则项目中不会再使用全局的Serlvet,则静态资源不能完成访问。
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>
DispathcerServlet的url-pattern依然采用 “/”,但追加配置
<!--
额外的增加一个handler,且其requestMapping: "/**" 可以匹配所有请求,但是优先级最低
所以如果其他所有的handler都匹配不上,请求会转向 "/**" ,恰好,这个handler就是处理静态资源的
处理方式:将请求转会到tomcat中名为default的Servlet
-->
<mvc:default-servlet-handler/>
- mapping是访问路径,location是静态资源存放的路径
- 将/html/** 中 /**匹配到的内容,拼接到 /hhh/后
http://…/html/a.html 访问 /hhh/a.html
<mvc:resources mapping="/html/**" location="/hhh/"/>
HttpMessageConverter 报文信息转换器 它可以将请求报文转为java对象,或 将 java对象转为响应报文
HttpMessageConverter 提供了
两个注解
@RequestBody 可以获取请求体 需要在控制器的方法形参上使用 使用请求体中的参数 给当前形参赋值 将请求体中的json数据转为java对象
@ResponseBody 作用在 控制器的方法上面 把响应的数据 转为 json
两个类 不常用了解
RequestEntity 写在方法 的 形参上 封装 请求体 请求头信息
ResponseEntity 是方法的返回值
<!-- Jackson springMVC默认的Json解决方案选择是 Jackson,所以只需要导入jackson的jar,即可使用。-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
@Controller public class JsonController{ @RequestMapping("/test1") @ResponseBody //将handler的返回值,转换成json(jackson),并将json响应给客户端。 public User hello1(){ System.out.println("hello world"); User user = new User(); return user; } // @ResponseBody还可以用在handler的返回值上 @RequestMapping("/test2") public @ResponseBody List<User> hello2(){ System.out.println("hello world"); List<User> users = Arrays.asList(new User(),new User()); return users; } // 如果返回值已经是字符串,则不需要转json,直接将字符串响应给客户端 @RequestMapping(value="/test3",produces = "text/html;charset=utf-8") //produces 防止中文乱码 @ResponseBody public String hello2(){ System.out.println("hello world"); return "你好"; } }
Controller类上加了@RestController注解,等价于在类中的每个方法上都加了@ResponseBody
@Controller @RestController public class JsonController{ @RequestMapping("/test1") public User hello1(){ System.out.println("hello world"); User user = new User(); return user; } //@ResponseBody还可以用在handler的返回值上 @RequestMapping("/test2") public List<User> hello2(){ System.out.println("hello world"); List<User> users = Arrays.asList(new User(),new User()); return users; } }
@RequestBody, 接收Json参数
class User{
private Integer id;
private String name;
private Boolean gender;
//set get
}
@RequestMapping("/users")
public String addUser(@RequestBody User user){//@RequestBody将请求体中的json数据转换为java对象
System.out.println("cap2");
System.out.println("Post user :"+user);
return "index";
}
var xhr = new XMLHttpRequest();
xhr.open("post","${pageContext.request.contextPath}/users?"+new Date().getTime());
xhr.setRequestHeader("content-type","application/json");//设置请求头
xhr.send('{"id":1,"name":"shine","gender":"true"}');//传递json串
//ajax
var user = {id:1,name:"shine"};
$.ajax({
url:'${pageContext.request.contextPath}/json2/test4',
type:'post',
contentType:"application/json",//声明请求参数类型为 json
data:JSON.stringify(user),// 转换js对象成json
success:function(ret){
console.log(ret);
}
});
记住:
js 对象 转为 json 串 方法: JSON.stringify(user);
json串转为 js 对象的方法 : JSON.parse(jsonstr);
@JsonFormat(pattern=“yyyy-MM-dd HH:mm:ss”,timezone = “GMT+8”)
public class User{
private Integer id;
private String name;
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date birth;
....
get/set
}
@JsonProperty(“new_name”)
public class User{
@JsonProperty("new_id") //不再使用原属性名,而是 "new_id"
private Integer id;
private String name;
....
get/set
}
输出的json:{“new_id”:xx,"name":"xx"}
@JsonIgnore
public class User{
private Integer id;
@JsonIgnore // 生成json时,忽略此属性
private String name;
....
get/set
}
输出json时: {"id":xx}
Jackson 默认会输出null值的属性,如果不需要,可以排除。
@JsonInclude(JsonInclude.Include.NON_NULL) //null值 属性不输出
@JsonInclude(value= JsonInclude.Include.NON_EMPTY) // empty属性不输出( 空串,长度为0的集合,null值)
public class User{
private Integer id;
@JsonInclude(JsonInclude.Include.NON_NULL) // 若"name==null" 忽略此属性
private String name;
@JsonInclude(value= JsonInclude.Include.NON_EMPTY) // 若hobby长度为0或==null 忽略此属性
private List<String> hobby;
....
get/set
}
如果name=null,且 hobby长度为0,则输出json时:{"id":xx}
@JsonSerialize(using = MySerializer.class) // 使用MySerializer输出某属性
public class User {
private Integer id;
private String name;
@JsonSerialize(using = MySerializer.class)
private Double salary = 10000.126;//在输出此属性时,使用MySerializer输出
....
get/set
}
则输出json时:{"id":xx,"name":"xxx","salary":10000.13}
public class MySerializer extends JsonSerializer<Double> {
// value即 Double salary的值
@Override
public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
// 将Double salary的值 四舍五入
String number = BigDecimal.valueOf(value).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
// 输出 四舍五入后的值
gen.writeNumber(number);
}
}
<!-- FastJson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
<mvc:annotation-driven>
<!-- 安装FastJson,转换器 -->
<mvc:message-converters>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<!-- 声明转换类型:json -->
<property name="supportedMediaTypes">
<list>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
@ResponseBody @RequestBody @RestController 使用方法不变
- 日期格式化:@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)
public class User implements Serializable{
@JSONField(serialize = false)
private Integer id;
@JSONField(name="NAME",serialzeFeatures = SerializerFeature.WriteNullStringAsEmpty)
private String name;
@JSONField(serialzeFeatures = SerializerFeature.WriteMapNullValue)
private String city;
@JSONField(format="yyyy/MM/dd")
private Date birth;
@JSONField(serializeUsing = MySerializer2.class)
private Double salary;
...
}
public class MySerializer2 implements ObjectSerializer {
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
int features) throws IOException {
Double value = (Double) object; // salary属性值
String text = value + "元";// 在salary后拼接 “元”
serializer.write(text); // 输出拼接后的内容
}
}
new User(1,null,null,new Date(),100.5);
// 如上对象,转换json:
{NAME:"",city:null,"birth":"2020/12/12","salary":"100.5元"}
Controller中的每个Handler自己处理异常
此种处理方案,异常处理逻辑,分散在各个handler中,不利于集中管理
public String xxx(){
try{
...
}catch(Exception1 e){
e.printStackTrace();
return "redirect:/xx/error1";
}catch(Exception2 e){
e.printStackTrace();
return "redirect:/xx/error2";
}
}
Controller中的每个Handler不再自己处理异常,而是直接throws所有异常。
定义一个“异常解析器” 集中捕获处理 所有异常
此种方案,在集中管理异常方面,更有优势!
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); } }
package com.glls.exception; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class CustomExceptionResolver implements HandlerExceptionResolver { /** * 异常解析器:主体逻辑 * 执行时刻:当handler中抛出异常时,会执行:捕获异常,并可以跳到错误页面 */ @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { CustomerException customerException = null; if(e instanceof CustomerException){ customerException = (CustomerException) e; }else{ // 如果系统抛出的异常 不是自定义异常 可以重新构造一个未知错误异常 customerException = new CustomerException("未知错误,请联系系统管理员"); } ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("error",customerException.getMessage()); modelAndView.setViewName("error"); return modelAndView; } }
<!-- 声明异常解析器 -->
<bean id="handlerExceptionResolver" class="com.glls.exception.CustomExceptionResolver"/>
package com.qf.java2110.exception; import com.qf.java2110.common.R; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.bind.MissingServletRequestParameterException; 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.bind.annotation.ResponseStatus; /** * @ClassName : CustomExceptionResolver * @Description : 第二种 全局异常处理器 返回 json 数据 不需要事先接口 借助 @ControllerAdvice 这个注解 */ @Component @ControllerAdvice // 对 controller 进行 增强 @ResponseBody public class CustomExceptionResolver2 { /** * 自定义异常 * @param ex CustomException * @return */ @ExceptionHandler(CustomerException.class) @ResponseStatus(value = HttpStatus.BAD_REQUEST) public R handleHttpMessageNotReadableException( CustomerException ex) { return new R(444, ex.getMessage()); } /** * 除零异常 * @param ex ArithmeticException * @return */ @ExceptionHandler(ArithmeticException.class) @ResponseStatus(value = HttpStatus.BAD_REQUEST) public R handleHttpMessageNotReadableException( ArithmeticException ex) { return new R(444, ex.getMessage()); } /** * 缺少请求参数异常 * @param ex MissingServletRequestParameterException * @return */ @ExceptionHandler(MissingServletRequestParameterException.class) @ResponseStatus(value = HttpStatus.BAD_REQUEST) public R handleHttpMessageNotReadableException( MissingServletRequestParameterException ex) { return new R(400, "缺少必要的请求参数"); } /** * 系统异常 预期以外异常 * @param ex * @return * * 项目中,我们一般都会比较详细的去拦截一些常见异常,拦截 Exception 虽然可以一劳永逸, * 但是不利于我们去排查或者定位问题。实际项目中,可以把拦截 Exception 异常写在 GlobalExceptionHandler * 最下面,如果都没有找到,最后再拦截一下 Exception 异常,保证输出信息友好。 */ @ExceptionHandler(Exception.class) @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) public R handleUnexpectedServer(Exception ex) { return new R(500, "系统发生异常,请联系管理员"); } }
作用:抽取handler (就是 controller) 中的冗余功能
执行顺序: preHandle–postHandle–afterCompletion
public class MyInter1 implements HandlerInterceptor{ //主要逻辑:在handler之前执行:抽取handler中的冗余代码 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("pre~~~"); /* response.sendRedirect("/springMVC_day2/index.jsp");//响应 return false;//中断请求 */ return true;//放行,后续的拦截器或handler就会执行 } //在handler之后执行:进一步的响应定制 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("post~~"); } //在页面渲染完毕之后,执行:资源回收 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("after~~"); } }
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/inter/test1"/>
<mvc:mapping path="/inter/test2"/>
<mvc:mapping path="/inter/test*"/> <!-- test开头 -->
<mvc:mapping path="/**"/> <!-- /** 任意多级任意路径 -->
<mvc:exclude-mapping path="/inter/login"/> <!--不拦截此路径-->
<bean class="com.glls.interceptor.MyInter1"></bean> <!--拦截器类-->
</mvc:interceptor>
</mvc:interceptors>
拦截器的应用场景 根据其特性 类似于 过滤器 ,比如 可以做 权限校验 日志记录 等等
面试题: 拦截器 于 过滤器的区别?
文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。
<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>
application/x-www-form-urlencoded
默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
multipart/form-data
这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
text/plain
除了把空格转换为 “+” 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
注意:
一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。
使用apache提供的工具类 commons-fileupload(麻烦)
使用servlet3.0版本,通过注解使用
使用SpirngMVC的MultipartResolver
Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类,因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件。
<!--文件上传-->
<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>
<%@ 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>
<!--文件上传配置-->
<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>
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>
<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"; }
@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(); }
防止暴力攻击,前端安全保障
<!-- 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>
<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>
<img src="${pageContext.request.contextPath}/captcha" style="width:85px" id="cap"/>
<script>
$(function(){
$("#cap").click(function(){
//刷新验证码
path = $(this).attr("src")+"?"+new Date().getTime();
$(this).attr("src",path);
});
});
</script>
是一种开发风格,遵从此风格开发软件,符合REST风格,则RESTFUL。
两个核心要求:
- 每个资源都有唯一的标识(URL)
- 不同的行为,使用对应的http-method
访问标识 | 资源 |
---|---|
http://localhost:8989/xxx/users | 所有用户 |
http://localhost:8989/xxx/users/1 | 用户1 |
http://localhost:8989/xxx/users/1/orders | 用户1的所有订单 |
请求方式 | 标识 | 意图 |
---|---|---|
GET | http://localhost:8989/xxx/users | 查询所有用户 |
POST | http://localhost:8989/xxx/users | 在所有用户中增加一个 |
PUT | http://localhost:8989/xxx/users | 在所有用户中修改一个 |
DELETE | http://localhost:8989/xxx/users/1 | 删除用户1 |
GET | http://localhost:8989/xxx/users/1 | 查询用户1 |
GET | http://localhost:8989/xxx/users/1/orders | 查询用户1的所有订单 |
POST | http://localhost:8989/xxx/users/1/orders | 在用户1的所有订单中增加一个 |
- **输出json:
@RequestMapping(value=“/users”,method = RequestMethod.GET)
等价
@GetMapping(“/users”)
@RestController public class RestController { @GetMapping("/users") public List<User> queryAllUsers(){ System.out.println("get"); List<User> users = .... return users; } @PostMapping("/users") public String addUser(@RequestBody User user){ System.out.println("Post user :"+user); return "{status:1}"; } @PutMapping("/users") public String updateUser(@RequestBody User user){ System.out.println("Put user" user:"+user); return "{status:1}"; } @GetMapping("/users/{id}") public String queryOneUser(@PathVariable Integer id){//@PathVariable 接收路径中的值 System.out.println("Get user id:"+id); return "{status:1}"; } @DeleteMapping("/users/{id}") public String deleteOneUser(@PathVariable Integer id){//@PathVariable 接收路径中的值 System.out.println("delete user id:"+id); return "{status:1}"; } }
<script> function putUser(){ // 发送更新请求 (增加请求发送方式也是如此) var xhr = new XMLHttpRequest(); //定义 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)); } });*/ } function delUser(){ // 发送删除请求 var xhr = new XMLHttpRequest(); //定义 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>
域:协议+IP+端口
http://localhost:8989
http://localhost:8080
http://www.baidu.com:80
Ajax发送请求时,不允许跨域,以防用户信息泄露。
当Ajax跨域请求时,响应会被浏览器拦截(同源策略),并报错。即浏览器默认不允许ajax跨域得到响应内容。
互相信任的域之间如果需要ajax访问,(比如前后端分离项目中,前端项目和后端项目之间),则需要额外的设置才可正常请求。
允许其他域访问
在被访问方的Controller类上,添加注解
@CrossOrigin("http://localhost:8080") //允许此域发请求访问
public class SysUserController {
....
}
携带对方cookie,使得session可用
在访问方,ajax中添加属性:withCredentials: true
$.ajax({
type: "POST",
url: "http://localhost:8989/web/sys/login",
...,
xhrFields: {
// 跨域携带cookie
withCredentials: true
}
});
或
var xhr = new XMLHttpRequest();
// 跨域携带cookie
xhr.withCredentials=true;
DispatcherServlet : 前端控制器 不需要程序员开发 由springmvc框架提供的,它的作用是 统一处理请求和响应 整个流程的控制中心 ,由他来调度其他组件 处理用户的请求
HandlerMapping: 处理器映射器 不需要程序员开发 有框架提供, 它的作用是根据 url ,method 等 信息 查找 handler 准确点说是 controller中的方法
Handler : 需要程序员开发的 controller
HandlerAdapter: 处理器适配器 不需要程序员开发 对handler 方法 进行 调用
ViewResolver: 视图解析器 不需要程序员开发 进行视图解析
View: 视图
Model: 数据
面试题: springmvc 的 核心组件有哪些? 或者 springmvc 的 执行流程是什么?
此时项目中有两个工厂
- DispatcherServlet 启动的springMVC工厂==负责生产C及springMVC自己的系统组件
- ContextLoaderListener 启动的spring工厂==负责生产其他所有组件
- springMVC的工厂会被设置为spring工厂的子工厂,可以随意获取spring工厂中的组件
- 整合过程,就是累加:代码+依赖+配置。然后将service注入给controller即可
两个工厂不能有彼此侵入,即,生产的组件不能有重合。
<!-- 告知SpringMVC 哪些包中 存在 被注解的类
use-default-filters=true 凡是被 @Controller @Service @Repository注解的类,都会被扫描
use-default-filters=false 默认不扫描包内的任何类, 只扫描include-filter中指定的类
只扫描被@Controller注解的类
-->
<context:component-scan base-package="com.zhj" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 告知Spring
唯独不扫描@Controller注解的类 -->
<context:component-scan base-package="com.zhj" use-default-filters="true">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dGyAJWw7-1682836813650)(E:\gitee\myrepo\my\springmvc\Pictures\image-20201102215248571.png)]
<?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>
<?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"?> <beans xmlns="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-scan base-package="com.qf.java2110" use-default-filters="true"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!--掌握 基于 AspectJ 的 注解 的 AOP实现 配置--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!--配置文件参数化(参数占位符)--> <context:property-placeholder location="classpath:db.properties" /> <!--与DruidDataSource集成(二选一)--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!--基本配置--> <!--基本配置--> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <!-- 配置获取连接等待超时的时间 --> <property name="maxWait" value="60000"/> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="60000"/> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="300000"/> </bean> <!-- 工厂bean:生成SqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--数据源属性--> <property name="dataSource" ref="dataSource"></property> <!--mybatis的配置文件--> <property name="configLocation" value="classpath:mybatis-config.xml"></property> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--扫描mapper 接口 自动创建mapper层代理对象 交给spring管理--> <property name="basePackage" value="com.qf.java2110.mapper"></property> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> </bean> <!--整合事务 第一步 配置事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--2.基于注解的形式 开启事务的注解--> <tx:annotation-driven transaction-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" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <!--自动扫描包,将原类名作为别名--> <package name="com.qf.java2110.pojo" /> </typeAliases> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins> <mappers> <!--扫描xml 映射文件--> <package name="com.qf.java2110.mapper"/> </mappers> </configuration>
logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="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> <appender name="logfile" class="ch.qos.logback.core.rolling.RollingFileAppender"> <Encoding>UTF-8</Encoding> <encoder> <pattern>%d %p [%t] [%c]:%L - %m%n</pattern> </encoder> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>DEBUG</level> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>log/%d{yyyy-MM-dd-HH'.log'}</fileNamePattern> </rollingPolicy> </appender> <logger name="org.springframework" level="WARN" /> <logger name="org.springframework.remoting" level="WARN" /> <logger name="org.springframework.scheduling.quartz" level="WARN" /> <logger name="org.springframework.data.jpa" level="DEBUG" /> <logger name="org.cometd" level="WARN" /> <logger name="ch.qos.logback" level="WARN" /> <logger name="com.springapp.mvc" level="DEBUG" /> <logger name="com.qf.mapper" level="DEBUG"></logger> <!-- <logger name="com.ibatis" level="DEBUG"></logger> --> <root level="ERROR"> <appender-ref ref="stdout" /> <appender-ref ref="logfile" /> </root> </configuration> ~~~xml <?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> <typeAliases> <!--自动扫描包,将原类名作为别名--> <package name="com.qf.java2110.pojo" /> </typeAliases> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins> <mappers> <!--扫描xml 映射文件--> <package name="com.qf.java2110.mapper"/> </mappers> </configuration>
logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="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> <appender name="logfile" class="ch.qos.logback.core.rolling.RollingFileAppender"> <Encoding>UTF-8</Encoding> <encoder> <pattern>%d %p [%t] [%c]:%L - %m%n</pattern> </encoder> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>DEBUG</level> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>log/%d{yyyy-MM-dd-HH'.log'}</fileNamePattern> </rollingPolicy> </appender> <logger name="org.springframework" level="WARN" /> <logger name="org.springframework.remoting" level="WARN" /> <logger name="org.springframework.scheduling.quartz" level="WARN" /> <logger name="org.springframework.data.jpa" level="DEBUG" /> <logger name="org.cometd" level="WARN" /> <logger name="ch.qos.logback" level="WARN" /> <logger name="com.springapp.mvc" level="DEBUG" /> <logger name="com.qf.mapper" level="DEBUG"></logger> <!-- <logger name="com.ibatis" level="DEBUG"></logger> --> <root level="ERROR"> <appender-ref ref="stdout" /> <appender-ref ref="logfile" /> </root> </configuration>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。