Spring MVC入门 1、Spring MVC 执行流程
(1)用户通过客户端向服务器发送请求,请求会被 Spring MVC 的前端控制器 DispatcherServlet 所拦截。
(2)DispatcherServlet 拦截到请求后,会调用 HandlerMapping 处理器映射器。
(3)处理器映射器根据请求的 URL 找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet。
(4)DispatcherServlet 会通过返回信息选择合适的 HandlerAdapter(处理器适配器)。
(5)HandlerAdapter 会调用并执行 Handler(处理器),这里的处理器指的就是程序中编写的 Controller 类,也被称为后端处理器。
(6)Controller 执行完成后,会返回一个 ModelAndView 对象,该对象中会包含视图名或包含模型和视图名。
(7)HandlerAdapter 将 ModelAndView 对象返回给 DispatcherServlet。
(8)DispatcherServlet 会根据 ModelAndView 对象选择一个合适的 ViewResolver(视图解析器)。
(9)ViewResolver 解析后,会向 DispatcherServlet 中返回具体的 View(视图)。
(10)DispatcherServlet 对 View 进行渲染(即将模型数据填充至视图中)。
(11)视图渲染结果会返回给客户端浏览器显示。
2、第一个 Spring MVC 程序 导入依赖
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 <dependencies > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > <scope > test</scope > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.2.0.RELEASE</version > </dependency > <dependency > <groupId > javax.servlet</groupId > <artifactId > servlet-api</artifactId > <version > 2.5</version > </dependency > <dependency > <groupId > javax.servlet.jsp</groupId > <artifactId > jsp-api</artifactId > <version > 2.2</version > </dependency > <dependency > <groupId > jstl</groupId > <artifactId > jstl</artifactId > <version > 1.2</version > </dependency > </dependencies >
web.xml
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 <?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" > <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-servlet.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > springmvc</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > </web-app >
classpath 只会到 class 路径中查找文件;
classpath* 不经包含 class 路径,还包括 jar 文件。
springmvc-servlet.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" 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" > <bean class ="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <bean class ="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /> <bean id ="internalResourceViewResolver" class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean > <bean id ="/hello" class ="com.yqx.controller.HelloController" /> </beans >
HelloController.java
1 2 3 4 5 6 7 8 9 public class HelloController implements Controller { @Override public ModelAndView handleRequest (HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { ModelAndView mv = new ModelAndView(); mv.setViewName("test" ); mv.addObject("msg" , "login" ); return mv; } }
test.jsp
1 2 3 4 5 6 7 8 9 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> 发送了一条msg:${msg} </body> </html>
3、注解实现 Spring MVC springmvc-servlet.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xmlns:mvc ="http://www.springframework.org/schema/mvc" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd" > <context:component-scan base-package ="com.yqx.Controller" /> <mvc:default-servlet-handler /> <mvc:annotation-driven /> <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean > </beans >
Controller.java
1 2 3 4 5 6 7 8 9 @Controller @RequestMapping("/test") public class MyController { @RequestMapping("/1") public String test (Model model) { model.addAttribute("msg" , "注解实现" ); return "annotation" ; } }
@Controller 代表组件,表示被 spring 容器托管,使用 @Repository、@Service 亦或是 @Component 也是一样的效果。
@RequestMapping 用来映射请求,通过它来指定控制器可以处理哪儿些 URL 请求,相当于 Servlet 在 web.xml 中的配置。
4、Restful 风格 4.1、什么是 Restful 风格 Restful 就是要一个资源定位及资源操作的风格。既不是标准也不是协议,只是一种风格。基于这个风格设计的软件会更简洁,更有层次,更易于实现缓存等机制。
1 2 3 4 https://www.baidu.com?search=123 https://www.baidu.com/123
4.2、路径变量 在 Spring MVC 中,我们可以通过 @PathVariable 来实现。
MyController.java
1 2 3 4 5 6 7 8 @Controller public class MyController { @RequestMapping("/restful/{a1}/{b1}") public String test1 (Model model, @PathVariable("a1") int a,@PathVariable("b1") int b) { model.addAttribute("res" , a-b); return "restful" ; } }
@PathVariable 中的参数值代表了 url 中对应的占位符名。如果不指定@PathVariable 的参数值,默认就会使用参数列表的参数名。
restful.jsp
1 2 3 4 5 6 7 8 9 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${res} </body> </html>
同时它可以指定提交的格式。
1 2 3 4 5 6 7 8 9 10 11 12 @RequestMapping(value = "/restful/{a}/{b}", method = RequestMethod.POST) public String test2 (Model model, @PathVariable int a,@PathVariable int b) { model.addAttribute("res" , a * b); return "restful" ; } @PostMapping("/restful/{a1}/{b1}") public String test3 (Model model, @PathVariable int a,@PathVariable int b) { model.addAttribute("res" , a * b); return "restful" ; }
5、重定向和转发 5.1、转发
浏览器的请求发送给组件1,组件1经过一些处理之后,将 request 和 response 对象传递
给组件2,由组件2继续处理,然后输出响应(也可以继续向其他组件“传递”)。
在上述转发的整个过程中,只涉及到一次
浏览器和服务器之间的“请求-响应”,转发过程中的组件共享同一个请求(request)和响应(reponse)对象。
抓饭只能在同一个应用的组件之间进行,不可以转发给其他应用的地址。
5.2、重定向
浏览器向组件1发送请求信息,组件1向浏览器发回一个重定向响应信息,该响应信息不包含具体的数据内容,只是在响应头信息中包含了需要重定向到的地址信息 (该地址可以是任何有效的 URL)。而浏览器收到该重定向响应后会自动地向该响应信息头中所指示的地址发出请求。
在上述重定向的整个过程中,涉及到两次
浏览器和服务器之间的“请求-响应”。
5.3、区别
转发是服务器内部跳转,数据不会丢失,浏览器只提交了一次请求,速度较快。
重定向是客户端二次跳转,数据会丢失,浏览器提交了二次请求,速度较慢。
做增删改查时最好使用重定向,否则每次刷新页面就相当于在请求一次,可能会做额外的操作,导致数据错误。
转发是服务器内部跳转,因此可以访问到 /WEB-INF 下的资源;而重定向是客户端跳转,因此无法访问到 /WEB-INF 下的资源。
5.3、代码实现 Controller.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Controller public class IndexController { @RequestMapping("/forward1") public String test1 (Model model) { model.addAttribute("msg" , "forward1" ); return "test" ; } @RequestMapping("/forward2") public String test2 (Model model) { model.addAttribute("msg" , "forward2" ); return "forward:/WEB-INF/jsp/test.jsp" ; } @RequestMapping("/redirect") public String test3 (Model model) { model.addAttribute("msg" , "redirect" ); return "redirect:/index.jsp" ; } }
6、请求参数 6.1、通过 url 传递一般参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Controller public class ParameterController { @RequestMapping("parameter1") public String test1 (String name, Model model) { model.addAttribute("name" , name); return "parameter" ; } @RequestMapping("parameter2") public String test2 (@RequestParam("username") String name, Model model) { model.addAttribute("name" , name); return "parameter" ; } }
6.2、通过 url 传递实体类参数 1 2 3 4 5 @RequestMapping("/parameter3") public String test3 (User user123, Model model) { model.addAttribute(user123); return "user" ; }
user.jsp
1 2 3 4 5 6 7 8 9 10 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <!--如果没有设置键值对的键,默认使用值的类型首字母小写作为键--> 姓名:${user.name}, 年龄:${user.age} </body> </html>
7、乱码问题 无论什么时候,只要是 web 应用服务项目,就不可能逃脱乱码的痛苦。
不过万幸的是,Spring 为我们提供了十分强大的过滤器,几乎可以解决所有的乱码问题,只需要在 web.xml 中配置即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 <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 >
8、JSON 在前后端进行数据交互时,需要一种统一的数据格式,否则后端传的数据前端不知道怎么解析就毫无意义了。
8.1、json 优点
JSON类似于XML,比XML更小、更快、更容易解析。但同时XML也有它的不可替代性,应根据使用场景进行更合适的选择;
JSON语法简单,很容易理解,并且对象信息自描述,数据传输量小不占用带宽;
JSON的可读性、可扩展性都非常好,编码难度也比较低,即使不借助工具也能写出比较规范的JSON
8.2、Jackson 导入依赖
1 2 3 4 5 <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > <version > 2.12.1</version > </dependency >
Controller.java
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 @RestController public class MyController { @RequestMapping("/json1") public String test1 () { return new User("余千禧" , "男" ).toString(); } @RequestMapping("/json2") public String test2 () throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); User user = new User("余千禧" , "男" ); String str = objectMapper.writeValueAsString(user); return str; } @RequestMapping("/json3") public String test3 () throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); User user1 = new User("余千禧1" , "男" ); User user2 = new User("余千禧2" , "男" ); User user3 = new User("余千禧3" , "男" ); User user4 = new User("余千禧4" , "男" ); User user5 = new User("余千禧5" , "男" ); List<User> list = new ArrayList<>(); list.add(user1); list.add(user2); list.add(user3); list.add(user4); list.add(user5); String str = objectMapper.writeValueAsString(list); return str; } }
结果
1 2 3 4 5 6 7 8 /json1 User(name=余千禧, sex=男) /json2 {"name":"余千禧","sex":"男"} /json3 [{"name":"余千禧1","sex":"男"},{"name":"余千禧2","sex":"男"},{"name":"余千禧3","sex":"男"},{"name":"余千禧4","sex":"男"},{"name":"余千禧5","sex":"男"}]
如果出现了乱码,可以复制下述代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <mvc:annotation-driven > <mvc:message-converters > <bean class ="org.springframework.http.converter.StringHttpMessageConverter" > <constructor-arg value ="UTF-8" /> </bean > <bean class ="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" > <property name ="objectMapper" > <bean class ="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" > <property name ="failOnEmptyBeans" value ="false" /> </bean > </property > </bean > </mvc:message-converters > </mvc:annotation-driven >
@RestController 修饰在类上,表示该类不会通过视图解析器,即该类中所有请求映射方法所返回的字符串当做普通的 String 类型来处理;
同理还有一个 @RequestBody 修饰在方法上,表示该方法不会通过视图解析器。
封装成工具类
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 package com.yqx.utils;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import java.text.SimpleDateFormat;public class JacksonUtil { public static String objectToJson (Object object) { return objectToJson(object, "yyyy-MM-dd HH:mm:ss" ); } public static String objectToJson (Object object, String format) { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setDateFormat(new SimpleDateFormat(format)); try { return objectMapper.writeValueAsString(object); } catch (JsonProcessingException e) { e.printStackTrace(); } return null ; } }
8.3、Fastjson 使用较 Jackson 而言更加便捷,同时默认就使用 “yyyy-MM-dd HH:mm:ss” 来格式化日期。
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 @RequestMapping("/json5") public String test5 () { User user1 = new User("余千禧1" , "男" ); User user2 = new User("余千禧2" , "男" ); User user3 = new User("余千禧3" , "男" ); User user4 = new User("余千禧4" , "男" ); User user5 = new User("余千禧5" , "男" ); List<User> list = new ArrayList<>(); list.add(user1); list.add(user2); list.add(user3); list.add(user4); list.add(user5); System.out.println("*******Java对象转JSON字符串*******" ); String str1 = JSON.toJSONString(list) ; System.out.println( "SON.toSONString(list)==>" +str1); String str2 = JSON.toJSONString(user1); System.out.println( "JSON.toJSONString(user1)==>" +str2); System.out.println("\n******JSON字符串转Java对象*******" ); User jp_user1=JSON.parseObject( str2,User.class); System.out.println("3SON.parseObject(str2,User.class)==>" +jp_user1); System.out.println("\n******Java对象转JSON对象******" ); JSONObject jsonObject1 = (JSONObject)JSON.toJSON(user2); System.out.println("(JSONObject) JSON.to3SON(user2)z=>" +jsonObject1.getString("name" )); System.out.println("\n******JSON对象转Java对象******" ); User to_java_user = JSON.toJavaObject(jsonObject1, User.class); System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>" + to_java_user); String str = JSON.toJSONString(list); return str; }
1 2 3 4 5 6 7 8 9 10 11 12 *******Java对象转JSON字符串******* SON.toSONString(list)==>[{"name" :"余千禧1" ,"sex" :"男" },{"name" :"余千禧2" ,"sex" :"男" },{"name" :"余千禧3" ,"sex" :"男" },{"name" :"余千禧4" ,"sex" :"男" },{"name" :"余千禧5" ,"sex" :"男" }] JSON.toJSONString(user1)==>{"name" :"余千禧1" ,"sex" :"男" } ******JSON字符串转Java对象******* 3SON.parseObject(str2,User.class)==>User(name=余千禧1 , sex=男) ******Java对象转JSON对象****** (JSONObject) JSON.to3SON(user2)z=>余千禧2 ******JSON对象转Java对象****** JSON.toJavaObject(jsonObject1, User.class)==>User(name=余千禧2 , sex=男)
9、SSM整合 9.1、配置文件代码(以后可以直接复制拿来用)
pom.xml
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 <?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" > <parent > <artifactId > SpringMVC</artifactId > <groupId > org.example</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > SpringMVC-05-SSM</artifactId > <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 5.2.0.RELEASE</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 5.1.47</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.2</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 2.0.6</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.2.0.RELEASE</version > </dependency > <dependency > <groupId > javax.servlet</groupId > <artifactId > servlet-api</artifactId > <version > 2.5</version > </dependency > <dependency > <groupId > jstl</groupId > <artifactId > jstl</artifactId > <version > 1.2</version > </dependency > <dependency > <groupId > javax.servlet.jsp</groupId > <artifactId > jsp-api</artifactId > <version > 2.2</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.18</version > </dependency > </dependencies > <build > <resources > <resource > <directory > src/main/resources</directory > <includes > <include > **/*.properties</include > <include > **/*.xml</include > </includes > <filtering > true</filtering > </resource > <resource > <directory > src/main/java</directory > <includes > <include > **/*.properties</include > <include > **/*.xml</include > </includes > <filtering > true</filtering > </resource > </resources > </build > </project >
applicationContext.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 <?xml version="1.0" encoding="UTF8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" > <context:component-scan base-package ="com.yqx.service" /> <import resource ="springmvc-servlet.xml" /> <import resource ="spring.xml" /> </beans >
mybatis-config.xml
1 2 3 4 5 6 7 8 9 <?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <typeAliases > <package name ="com.yqx.pojo" /> </typeAliases > </configuration >
spring.xml
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 <?xml version="1.0" encoding="UTF8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" > <context:property-placeholder location ="classpath:db.properties" /> <bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name ="driverClassName" value ="${jdbc.driver}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> </bean > <bean name ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> <property name ="configLocation" value ="classpath:mybatis-config.xml" /> <property name ="mapperLocations" value ="classpath*:com/yqx/mapper/*.xml" /> </bean > <bean name ="sqlSessionTemplate" class ="org.mybatis.spring.SqlSessionTemplate" > <constructor-arg index ="0" ref ="sqlSessionFactory" /> </bean > <bean class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean > </beans >
springmvc-servlet.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?xml version="1.0" encoding="UTF8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc ="http://www.springframework.org/schema/mvc" xmlns:context ="http://www.springframework.org/schema/context" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" > <mvc:default-servlet-handler /> <mvc:annotation-driven /> <context:component-scan base-package ="com.yqx.controller" /> <bean name ="internalResourceViewResolver" class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean > </beans >
web.xml
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 <?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" > <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:applicationContext.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 >
9.2 踩雷 (1)db.properties
报错信息如下。
1 2 org.apache.ibatis.exceptions.PersistenceException: Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: Access denied for user '11499' @'localhost' (using password: YES)
这是因为 db.properties 里面 username 必须用 jdbc.username
。否则 username 就变成了系统管理员(‘11499‘@’localhost’)的名字。
1 2 3 4 5 jdbc.driver =com.mysql.jdbc.Driver jdbc.url =jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=utf8 jdbc.username =root jdbc.password =123456
将 spring.xml 中 DataSource 属性也一并修改。
1 2 3 4 5 6 <bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name ="driverClassName" value ="${jdbc.driver}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> </bean >
(2)mapper.java
报错信息如下。
1 Type interface com .yqx .mapper .BookMapper is not known to the MapperRegistry .
这个问题有点傻,因为 mapper.xml 文件我都是直接使用模板,如下。
但这个项目是 BookMapper,然后就忘记改了…
1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.yqx.mapper.UserMapper" > </mapper >
(3)web.xml
报错信息如下。
1 org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.yqx.service.BookMapperImpl' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org .springframework.beans.factory.annotation.Autowired(required=true )}
因为在 web.xml 中只引入了 springmvc-servlet.xml,因此不可能有 BookMapperImpl 这个 bean。
1 <param-value > classpath:springmvc-servlet.xml</param-value >
只需要引入总的配置文件 applicationContext.xml ,再在 applicaitonContext.xml 中引入所有其他文件就行。
1 <param-value > classpath:applicationContext.xml</param-value >
1 2 <import resource ="springmvc-servlet.xml" /> <import resource ="spring.xml" />
(4)post 表单提交出现乱码
添加过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 <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 >
(5)xml 文件编码
报错信息
1 com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: 1 字节的 UTF-8 序列的字节 1 无效
该错误是由一些配置文件引起的:如applicationContext.xml的编码问题等。
对于Maven 项目,在项目依赖配置文件 pom.xml 中加入构建项目编码属性(注意顺序):
1 2 3 <properties > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > </properties >
10、Ajax 10.1、异步 异步(Asynchronous, async)是与同步(Synchronous, sync)相对的概念。
在我们学习的传统单线程编程中,程序的运行是同步的(同步不意味着所有步骤同时运行,而是指步骤在一个控制流序列中按顺序
执行)。而异步的概念则是不保证同步的概念,也就是说,一个异步过程的执行将不再与原有的序列有顺序关系。
简单来理解就是:同步按你的代码顺序执行,异步不按照代码顺序执行,异步的执行效率更高。
10.2、什么时候使用异步编程 在前端编程中(甚至后端有时也是这样),我们在处理一些简短、快速的操作时,例如计算 1 + 1 的结果,往往在主线程中就可以完成。主线程作为一个线程,不能够同时接受多方面的请求。所以,当一个事件没有结束时,界面将无法处理其他请求。
现在有一个按钮,如果我们设置它的 onclick 事件为一个死循环,那么当这个按钮按下,整个网页将失去响应。
为了避免这种情况的发生,我们常常用子线程来完成一些可能消耗时间足够长以至于被用户察觉的事情,比如读取一个大文件或者发出一个网络请求 。因为子线程独立于主线程,所以即使出现阻塞也不会影响主线程的运行。但是子线程有一个局限:一旦发射了以后就会与主线程失去同步,我们无法确定它的结束,如果结束之后需要处理一些事情,比如处理来自服务器的信息,我们是无法将它合并到主线程中去的。
为了解决这个问题,JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理 。
回调函数
回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终。
1 2 3 setTimeout (function ( ) { document .getElementById("demo" ).innerHTML="RUNOOB!" ; }, 3000 );
这段程序中的 setTimeout 就是一个消耗时间较长(3 秒)的过程,它的第一个参数是个回调函数,第二个参数是毫秒数,这个函数执行之后会产生一个子线程,子线程会等待 3 秒,然后执行回调函数 “print”,在命令行输出 “RUNOOB!”。
10.3、利用 JQuery 实现 Ajax 初体验
jsp 页面,js 写在 html 前,要加$(function())
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 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <script src="${pageContext.request.contextPath}/static/js/jquery.js" ></script> <script> $(function (){ $("#btn" ).click(function (){ $.post("/ajax1" , function (data){ let html = "<table><thead><td>姓名</td><td>年龄</td></thead><tbody>" ; for (let i=0 ;i<data.length;i++) { html += "<tr>" + "<td>" + data[i].name + "</td>" + "<td>" + data[i].age + "</td>" + "</tr>" } html += "</tbody></table>" console.log(html) $("#content" ).html(html) }) }) }) </script> <html> <head> <title>Title</title> </head> <body> <button id="btn" >查询</button> <div id="content" > </div> </body> </html>
controller.java
1 2 3 4 5 6 7 8 9 10 11 @RestController public class AjaxController { @RequestMapping("/ajax1") public List<User> test1 () { List<User> list = new ArrayList<>(); list.add(new User("余千禧" , 1 )); list.add(new User("紫梦沁香" , 2 )); list.add(new User("自杀之王" , 3 )); return list; } }
No converter found for return value of type: class java.util.ArrayList 是因为无法将返回的对象转换为 Json 输出到网页上,只需导入 Jackson 或 FastJson 的 jar 包就行
验证用户名密码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @RequestMapping("/ajax2") public String test2 (String name, String pwd) { String msg="" ; if (name!=null ){ if (name.equals("yqx" )){ msg="ok" ; }else { msg="用户名输入错误" ; } } if (pwd!=null ){ if (pwd.equals("123" )){ msg="ok" ; }else { msg="密码输入错误" ; } } return msg; }
返回时出现字符串乱码请查看8.2
jsp 页面
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 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <script src="${pageContext.request.contextPath}/static/js/jquery.js" ></script> <script> function name_blur () { $.post("/ajax2" , {"name" : $("#name" ).val()}, function (data){ if (data == "ok" ){ $("#span1" ).text(data).css("color" , "green" ); }else { $("#span1" ).text(data).css("color" , "red" ); } }) } function pwd_blur () { $.post("/ajax2" , {"pwd" : $("#pwd" ).val()}, function (data){ if (data == "ok" ){ $("#span2" ).text(data).css("color" , "green" ); }else { $("#span2" ).text(data).css("color" , "red" ); } }) } </script> <html> <head> <title>Title</title> </head> <body> <form> 用户名:<input id="name" type="text" onblur="name_blur()" > <span id="span1" ></span> <br> 密码:<input id="pwd" type="password" onblur="pwd_blur()" > <span id="span2" ></span> </form> </body> </html>
11、拦截器 在系统中,经常需要在处理用户请求之前和之后执行一些行为,例如检测用户的权限,或者将请求的信息记录到日志中 ,即平时所说的“权限检测
”及“日志记录
”。当然不仅仅这些,所以需要一种机制,拦截用户的请求,在请求的前后添加处理逻辑 。
Spring MVC 提供了 Interceptor 拦截器机制,用于请求的预处理和后处理。
MyInterceptor.java,需实现 HandlerInterceptor
接口。
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 package com.yqx.interceptor;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;public class MyInterceptor implements HandlerInterceptor { @Override public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion方法在控制器的处理请求方法执行完成后执行,即视图渲染结束之后执行" ); } @Override public void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行" ); } @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle方法在控制器的处理请求方法调用之前执行" ); HttpSession session = request.getSession(); if (session.getAttribute("name" ) == null ){ response.sendRedirect("/toLogin" ); return false ; } return true ; } }
preHandle( ):该方法在控制器的处理请求方法前执行,其返回值表示是否中断后续操作,返回 true 表示继续
向下执行,返回 false 表示中断
后续操作。
postHandle( ):该方法在控制器的处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步的修改。
afterCompletion( ):该方法在控制器的处理请求方法执行完成后执行,即视图渲染结束后执行,可以通过此方法实现一些资源清理、记录日志信息等工作。
写完拦截器需在Spring MVC 的配置文件中进行配置。
1 2 3 4 5 6 7 8 9 10 11 12 <mvc:interceptors > <mvc:interceptor > <mvc:mapping path ="/toMain" /> <bean class ="com.yqx.interceptor.MyInterceptor" /> </mvc:interceptor > </mvc:interceptors >