[TOC]
一、SpringMVC
1.1 引言
java开源框架,Spring Framework的一个独立模块。
MVC框架,在项目中开辟MVC层次架构
对控制器中的功能 包装 简化 扩展践行工厂模式,功能架构在工厂之上
1.2 MVC架构 1.2.1 概念
名称
职责
Model
模型:即业务模型,负责完成业务中的数据通信处理,对应项目中的 service和dao
View
视图:渲染数据,生成页面。对应项目中的Jsp
Controller
控制器:直接对接请求,控制MVC流程,调度模型,选择视图。对应项目中的Servlet
1.2.2 好处
二、开发流程
2.1 导入依赖 1 2 3 4 5 <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.1.6.RELEASE</version > </dependency >
2.2 配置核心(前端)控制器
作为一个MVC框架,首先要解决的是:如何能够收到请求!
所以MVC框架大都会设计一款前端控制器,选型在 Servlet 或 Filter两者之一,在框架最前沿率先工作,接收所有请求。
此控制器在接收到请求后,还会负责springMVC的核心的调度管理,所以既是前端又是核心。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <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 > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > mvc</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping >
2.3 后端控制器
等价于之前定义的Servlet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Controller @RequestMapping("/hello") public class HelloController { @RequestMapping("/test1") public String hello1 () { System.out.println("hello world" ); return "index" ; } @RequestMapping("/test2") public String hello2 () { System.out.println("hello c9" ); return "views/users" ; } }
2.4 配置文件
默认名称:核心控制器名-servet.xml 默认位置:WEB-INF
随意名称:mvc.xml 随意位置:resources 但需要配置在核心控制器中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <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" > <context:component-scan base-package ="com.qf.controller" > </context:component-scan > <mvc:annotation-driven > </mvc:annotation-driven > <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="prefix" value ="/" > </property > <property name ="suffix" value =".jsp" > </property > </bean > </beans >
2.5 访问 1 2 http://localhost:8989/hello/test1 http://localhost:8989/hello/test2
三、接收请求参数
3.1 基本类型参数
请求参数和方法的形参 同名即可
springMVC默认可以识别的日期字符串格式为: YYYY/MM/dd HH:mm:ss 通过@DateTimeFormat可以修改默认日志格式
1 2 3 4 5 6 7 8 9 10 @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" ; }
3.2 实体收参【重点
】
请求参数和实体的属性 同名即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class User { private Integer id; private String name; @DateTimeFormat(pattern="yyyy-MM-dd") private Date birth; private Boolean gender; } @RequestMapping("/test2") public String testParam2 (User user) { System.out.println("test param2" ); System.out.println("user:" +user); return "index" ; }
3.3 数组收参
简单类型的 数组
1 2 3 4 5 6 7 <form > ...... <input type ="checkbox" name ="hobby" value ="fb" /> 足球 <input type ="checkbox" name ="hobby" value ="bb" /> 篮球 <input type ="checkbox" name ="hobby" value ="vb" /> 排球 </form >
1 2 3 4 5 6 7 8 @RequestMapping("/test3") public String testParam3 (String[] hobby) { for (String h:hobby){ System.out.print(h+" " ); } return "index" ; }
3.4 集合收参 【了解】 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class UserList { private List<User> users; } @RequestMapping("/test4") public String testParam4 (UserList userList) { for (User user:userList.getUsers()){ System.out.println(user); } return "index" ; }
3.5 路径参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @RequestMapping("/hello/{id}") public String testParam5 (@PathVariable("id") Integer id) { System.out.println("id:" +id); return "index" ; } @RequestMapping("/hello/{username}") public String testParam6 (@PathVariable("username") String name) { System.out.println("username:" +name); return "index" ; }
3.6 中文乱码
首先,页面中字符集统一
1 2 JSP : <%@page pageEncoding="utf-8" %> HTML : <meta charset="UTF-8" >
其次,tomcat中字符集设置,对get请求中,中文参数乱码有效
1 Tomcat配置:URIEncoding=utf-8
最后,设置此filter,对post请求中,中文参数乱码有效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <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 >
四、跳转
4.1 转发 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @RequestMapping("/forw") class ForwardController { @RequestMapping("/test1") public String testForward () { System.out.println("test forward1" ); return "forward:/views/users.jsp" ; } @RequestMapping("/test2") public String testForward2 () { System.out.println("test forward2" ); return "forward:/forw/test1" ; } }
4.2 重定向 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @RequestMapping("/redir") class RedirectController { @RequestMapping("/test1") public String testRedirect1 () { System.out.println("test redirect1" ); return "redirect:/redir/test1" ; } @RequestMapping("/test2") public String testRedirect2 () { System.out.println("test redirect2" ); return "redirect:/view/user.jsp" ; } }
4.3 跳转细节
在增删改之后,为了防止请求重复提交,重定向跳转
在查询之后,可以做转发跳转
五、传值
C得到数据后,跳转到V,并向V传递数据。进而V中可以渲染数据,让用户看到含有数据的页面
转发跳转:Request作用域
重定向跳转:Session作用域
5.1 Request和Session 1 2 3 4 5 6 7 8 9 @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 "forward:/WEB-INF/test2.jsp" ; }
5.2 JSP中取值
建议:重点复习 EL JSTL
1 2 3 4 <fmt:formatDate value="${sessionScope.user.birth}" pattern="yyyy-MM-dd" /> <br/> ${sessionScope.user.birth} <br> ${requestScope.age}
5.3 Model 1 2 3 4 5 6 7 8 9 @RequestMapping("/test") public String testData (Model model) { model.addAttribute("name" , "张三" ); return "index" ; } ${requestScope.name}
5.4 ModelAndView 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @RequestMapping("/test") public ModelAndView testData () { ModelAndView mv = new ModelAndView (); mv.setViewName("forward:/index.jsp" ); mv.addObject("age" ,18 ); return mv; } ${requestScope.age}
5.5 @SessionAttributes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Controller @SessionAttributes({"gender","name"}) public class UserController { @RequestMapping("/hello") public String hello (Model m) { m.addAttribute("gender" ,true ); mv.addObject("name" ,"zhj" ); return "index" ; } @RequestMapping("/hello2") public String hello (SessionStatus status) { 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结尾!!
1 2 3 4 5 6 7 8 <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依然采用 “/“,但追加配置
1 2 3 4 5 6 <mvc:default-servlet-handler />
6.4 解决方案3
mapping是访问路径,location是静态资源存放的路径
将/html/** 中 /**匹配到的内容,拼接到 /hhh/后 http://…./html/a.html 访问 /hhh/a.html
1 <mvc:resources mapping ="/html/**" location ="/hhh/" />
七、Json处理
7.1 导入依赖 1 2 3 4 5 6 <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > <version > 2.9.8</version > </dependency >
7.2 使用@ResponseBody 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Controller public class JsonController { @RequestMapping("/test1") @ResponseBody public User hello1 () { System.out.println("hello world" ); User user = new User (); return user; } @RequestMapping("/test2") public @ResponseBody List<User> hello2 () { System.out.println("hello world" ); List<User> users = Arrays.asList(new User (),new User ()); return users; } @RequestMapping(value="/test3",produces = "text/html;charset=utf-8") @ResponseBody public String hello2 () { System.out.println("hello world" ); return "你好" ; } }
7.3 使用@RestController
Controller类上加了@RestController注解,等价于在类中的每个方法上都加了@ResponseBody
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Controller @RestController public class JsonController { @RequestMapping("/test1") public User hello1 () { System.out.println("hello world" ); User user = new User (); return user; } @RequestMapping("/test2") public List<User> hello2 () { System.out.println("hello world" ); List<User> users = Arrays.asList(new User (),new User ()); return users; } }
7.4 使用@RequestBody
@RequestBody , 接收Json参数
7.4.1 定义Handler 1 2 3 4 5 6 class User { private Integer id; private String name; private Boolean gender; }
1 2 3 4 5 6 @RequestMapping("/users") public String addUser (@RequestBody User user) { System.out.println("cap2" ); System.out.println("Post user :" +user); return "index" ; }
7.4.2 Ajax发送json 1 2 3 4 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"}' );
1 2 3 4 5 6 7 8 9 10 11 var user = {id :1 ,name :"shine" };$.ajax ({ url :'${pageContext.request.contextPath}/json2/test4' , type :'post' , contentType :"application/json" , data :JSON .stringify (user), success :function (ret ){ console .log (ret); } });
7.5 Jackson常用注解 7.5.1 日期格式化
@JsonFormat(pattern=”yyyy-MM-dd HH:mm:ss”,timezone = “GMT+8”)
1 2 3 4 5 6 7 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 }
7.5.2 属性名修改
@JsonProperty(“new_name”)
1 2 3 4 5 6 7 8 public class User { @JsonProperty("new_id") private Integer id; private String name; .... get/set } 输出的json:{“new_id”:xx,"name" :"xx" }
7.5.3 属性忽略
@JsonIgnore
1 2 3 4 5 6 7 8 public class User { private Integer id; @JsonIgnore private String 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值)
1 2 3 4 5 6 7 8 9 10 public class User { private Integer id; @JsonInclude(JsonInclude.Include.NON_NULL) private String name; @JsonInclude(value= JsonInclude.Include.NON_EMPTY) private List<String> hobby; .... get/set } 如果name=null ,且 hobby长度为0 ,则输出json时:{"id" :xx}
7.5.5 自定义序列化
@JsonSerialize(using = MySerializer.class) // 使用MySerializer输出某属性
1 2 3 4 5 6 7 8 9 public class User { private Integer id; private String name; @JsonSerialize(using = MySerializer.class) private Double salary = 10000.126 ; .... get/set } 则输出json时:{"id" :xx,"name" :"xxx" ,"salary" :10000.13 }
1 2 3 4 5 6 7 8 9 10 11 public class MySerializer extends JsonSerializer <Double> { @Override public void serialize (Double value, JsonGenerator gen, SerializerProvider serializers) throws IOException { String number = BigDecimal.valueOf(value).setScale(2 , BigDecimal.ROUND_HALF_UP).toString(); gen.writeNumber(number); } }
7.6 FastJson 7.6.1 导入依赖 1 2 3 4 5 6 <dependency > <groupId > com.alibaba</groupId > <artifactId > fastjson</artifactId > <version > 1.2.54</version > </dependency >
7.6.2 安装FastJson 1 2 3 4 5 6 7 8 9 10 11 12 13 <mvc:annotation-driven > <mvc:message-converters > <bean class ="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter" > <property name ="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)
1 2 3 4 5 6 7 8 9 10 11 12 13 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; ... }
1 2 3 4 5 6 7 8 9 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; String text = value + "元" ; serializer.write(text); } }
1 2 3 4 new User (1 ,null ,null ,new Date (),100.5 );{NAME:"" ,city:null ,"birth" :"2020/12/12" ,"salary" :"100.5元" }
八、异常解析器
8.1 现有方案,分散处理
Controller中的每个Handler自己处理异常
此种处理方案,异常处理逻辑,分散在各个handler中,不利于集中管理
1 2 3 4 5 6 7 8 9 10 11 public String xxx () { try { ... }catch (Exception1 e){ e.printStackTrace(); return "redirect:/xx/error1" ; }catch (Exception2 e){ e.printStackTrace(); return "redirect:/xx/error2" ; } }
8.2 异常解析器,统一处理
Controller中的每个Handler不再自己处理异常,而是直接throws所有异常。
定义一个“异常解析器” 集中捕获处理 所有异常
此种方案,在集中管理异常方面,更有优势!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class MyExResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ex.printStackTrace(); ModelAndView mv = new ModelAndView (); if (ex instanceof Exception1) { mv.setViewName("redirect:/xxx/error1" ); }else if (ex instanceof Exception2){ mv.setViewName("redirect:/xxx/error2" ); }else { mv.setViewName("redirect:/xxx/error" ); } return mv; } }
1 2 <bean class ="com.baizhi.exception.resolver.MyExResolver" > </bean >
九、拦截器
9.1 作用
作用:抽取handler中的冗余功能
9.2 定义拦截器
执行顺序: preHandle–postHandle–afterCompletion
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class MyInter1 implements HandlerInterceptor { @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("pre~~~" ); return true ; } @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~~" ); } }
9.3 配置拦截路径 1 2 3 4 5 6 7 8 9 10 <mvc:interceptors > <mvc:interceptor > <mvc:mapping path ="/inter/test1" /> <mvc:mapping path ="/inter/test2" /> <mvc:mapping path ="/inter/test*" /> <mvc:mapping path ="/inter/**" /> <mvc:exclude-mapping path ="/inter/a/**" /> <bean class ="com.baizhi.interceptor.MyInter1" > </bean > </mvc:interceptor > </mvc:interceptors >
十、上传
10.1 导入jar 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <dependency > <groupId > commons-io</groupId > <artifactId > commons-io</artifactId > <version > 2.4</version > </dependency > <dependency > <groupId > commons-fileupload</groupId > <artifactId > commons-fileupload</artifactId > <version > 1.3.3</version > <exclusions > <exclusion > <groupId > javax.servlet</groupId > <artifactId > servlet-api</artifactId > </exclusion > </exclusions > </dependency >
10.2 表单 1 2 3 4 5 <form action ="${pageContext.request.contextPath }/upload/test1" method ="post" enctype ="multipart/form-data" > file: <input type ="file" name ="source" /> <br > <input type ="submit" value ="提交" /> </form >
10.3 上传解析器 1 2 3 4 5 6 7 8 <bean id ="multipartResolver" class ="org.springframework.web.multipart.commons.CommonsMultipartResolver" > <property name ="maxUploadSize" value ="1048576" > </property > </bean >
10.4 Handler 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @RequestMapping("/test1") public String hello1 (String username,MultipartFile source,HttpSession session) { String filename = source.getOriginalFilename(); String unique = UUID.randomUUID().toString(); String ext = FilenameUtils.getExtension(filename); String uniqueFileName = unique+"." +ext; System.out.println("唯一的文件名:" +uniqueFileName); String type = source.getContentType(); System.out.println("filename:" +filename+" type:" +type); String real_path = session.getServletContext().getRealPath("/upload_file" ); System.out.println("real_path:" +real_path); source.transferTo(new File (real_path+"\\" +uniqueFileName)); return "index" ; }
十一、下载
11.1 超链 1 <a href ="${pageContext.request.contextPath}/download/test1?name=Koala.jpg" > 下载</a >
11.2 Handler 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @RequestMapping("/test1") public void hello1 (String name,HttpSession session,HttpServletResponse response) { System.out.println("name:" +name); String path = session.getServletContext().getRealPath("/upload_file" ); String real_path = path+"\\" +name; response.setHeader("content-disposition" ,"attachment;filename=" +name); IOUtils.copy(new FileInputStream (real_path), response.getOutputStream()); }
十二、验证码
12.1 作用
防止暴力攻击,前端安全保障
12.2 导入jar 1 2 3 4 5 6 7 8 9 10 11 12 <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 >
12.3 声明验证码组件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <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 > <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 >
12.4 Page 1 2 3 4 5 6 7 8 9 10 <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
13.1 开发风格
是一种开发风格,遵从此风格开发软件,符合REST风格,则RESTFUL。
两个核心要求:
每个资源都有唯一的标识(URL)
不同的行为,使用对应的http-method
13.2 优点
13.3 使用 13.3.1 定义Rest风格的 Controller
@RequestMapping(value=”/users”,method = RequestMethod.GET)
等价
@GetMapping(“/users”)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @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 }"; } }
13.3.2 Ajax请求 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <script > function putUser ( ){ var xhr = new XMLHttpRequest (); 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 ; console .log (JSON .parse (ret)); } } } function delUser ( ){ var xhr = new XMLHttpRequest (); 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 >
十四、跨域请求
14.1 域
域:协议+IP+端口
14.2 Ajax跨域问题
Ajax发送请求时,不允许跨域,以防用户信息泄露。
当Ajax跨域请求时,响应会被浏览器拦截(同源策略),并报错。即浏览器默认不允许ajax跨域得到响应内容。
互相信任的域之间如果需要ajax访问,(比如前后端分离项目中,前端项目和后端项目之间),则需要额外的设置才可正常请求。
14.3 解决方案
允许其他域访问
在被访问方的Controller类上,添加注解
1 2 3 4 @CrossOrigin("http://localhost:8080") public class SysUserController { .... }
1 2 3 4 5 6 7 8 9 10 11 12 13 $.ajax ({ type : "POST" , url : "http://localhost:8989/web/sys/login" , ..., xhrFields : { withCredentials : true } }); 或 var xhr = new XMLHttpRequest ();xhr.withCredentials =true ;
十五、SpringMVC执行流程
十六、Spring整合
16.1 整合思路
此时项目中有两个工厂
DispatcherServlet 启动的springMVC工厂==负责生产C及springMVC自己的系统组件
ContextLoaderListener 启动的spring工厂==负责生产其他所有组件
springMVC的工厂会被设置为spring工厂的子工厂,可以随意获取spring工厂中的组件
整合过程,就是累加:代码+依赖+配置。然后将service注入给controller即可
16.2 整合技巧
两个工厂不能有彼此侵入,即,生产的组件不能有重合。
1 2 3 4 5 6 7 8 <context:component-scan base-package ="com.zhj" use-default-filters ="false" > <context:include-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /> </context:component-scan >
1 2 3 4 5 <context:component-scan base-package ="com.zhj" use-default-filters ="true" > <context:exclude-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /> </context:component-scan >