Spring MVC
工作原理
- 用户发送请求至前端控制器(DispatcherServlet)。
- 前端控制器委托请求至Controller。
- Controller再去调用Model(service、dao)去请求数据。
- 数据请求回来再由Controller响应至前端控制器。
- 前端控制器将响应来的数据在视图层渲染。
- 最后将数据显示给用户。
SPring MVC 的web围绕DispatcherServlet设计,DispathcherServlet可以将请求分发到不同的控制器。
DispatcherServlet本质也是servlet
SpringMVC流程:
- 用户发送请求,请求到前端控制器webapp.xml(DispatcherServlet)
- DispatcherServlet将请求交给处理器(controller)
- 控制器去调用业务对象(service)并拿到结果返回一个ModelAndView(模型装数据,并且添加一个视图的名字)给前端控制器webapp.xml(DispatcherServlet)
- 前端控制器去将数据渲染至视图中。
- 返回至用户
搭建SpringMVC
-
pom.xml添加依赖
<!--导入依赖--> <dependencies> <!--单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--spring框架--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!--servlet--> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <!--jsp--> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> </dependency> <!--jstl标签库--> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies>
-
注册DispatcherServlet至web.xml。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--注册DispatcherServlet--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--关联一个springmvc的配置文件,【param-name】-servlet.xml--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:springmvc-servlet.xml</param-value> </init-param> <!--启动级别-1--> <load-on-startup>1</load-on-startup> </servlet> <!--/匹配所有请求(不包括.jsp)--> <!--/*匹配所有请求(包括.jsp)--> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
-
配置springmvc-servlet.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd "> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <context:component-scan base-package="com.sx.controller"></context:component-scan> <mvc:annotation-driven/> <!--视图解析器:DispatcherServlet 给他的 ModelAndView 1.获取一个ModelAndView数据 2.解析ModelAndView视图名 3.拼接视图名,找到对应的视图 4.将数据渲染到视图 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean> </beans>
-
在webapp创建对应视图。(jsp等)
-
创建controller(加入controller注解将它装配到bean)。
-
创建方法,处理数据,返回字符串,字符串就是视图的名字,会被视图解析器处理。
-
加入@ReauestMapping("请求名")。(类上也可以加ReauestMapping)相当于多访问一层。
关于重定向和转发
- 使用视图解析器的话,return视图名称默认就是转发
- 重定向的话,在return的视图字符串中加入redirect:即可。
关于前端提交数据
提交数据
-
数据名和形参列表名相同的话可直接接收。
-
数据名和形参列表名不同的话需加入RequestParam("")注解转换(尽量全部加上)。
-
前端提交实体类可以用实体类去接收。
对象和json转换
后端向前端传递json字符串
-
jackson包
<!--jackson:对后端的json字符串进行转换的工具--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency>
可将对象/List/SimpleDateFormat等类型转换为json类型
ObjectMapper mapper = new ObjectMapper(); String user = mapper.writeValueAsString(new User(1, "张三", "女"));
使用writeValueAsString获取时间并以json类型响应至前端
//关闭日期转换为时间戳 mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false); //指定日期格式 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-YY-dd HH:mm:hh"); //SimpleDateFormat转为String mapper.writeValueAsString(sdf); //new一个Date Date date = new Date(); return mapper.writeValueAsString(date);
-
@RequestBody
将服务器端返回的对象转换为json对象响应回去
-
出现中文???解决方法:
-
在@RequestMapping注解上加入produces = "application/json;charset=utf-8"
@RequestMapping(value = "/test",produces = "application/json;charset=utf-8")
-
在springmvc核心配置文件中加入
<!--解决后端向前端传josn字符串时中文?的问题--> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <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>
-
前端json和对象类型的互换
<script type="text/javascript">
var user = {
ID:1,
name:"sx",
gender:"男"
}
//对象转json
var s = JSON.stringify(user);
//json转对象
var user = JSON.parse(s);
</script>
AJAX异步交互
AJAX是一种无需重新加载整个网页的情况下,能够更新部分网页的技术。可以增强B/S的体验性。
AJAX例子:
- 注册时,输入用户名可直接提示用户名是否可用。
- 登陆时提示用户名密码错误。
- 删除数据时,将ID发送到后台,后台在数据库删除后,页面DOM处也进行删除。
使用AJAX
-
导入jQuery文件
-
对应事件函数中写ajax主体
$.ajax({ url:"ajaxTest", //请求地址 data:{ //传入参数 name:$("#textName").val() }, success:function (data) { //执行成功返回数据 data为return的数据 alert(data) var user = JSON.parse(data); console.log(user); } });
-
对应controller
@RequestMapping("ajaxTest") //接收请求 @ResponseBody //转json String ajaxTest(String name) throws IOException { System.out.println(name); if ("admin".equals(name)){ ObjectMapper mapper = new ObjectMapper(); //jackson方法 String s = mapper.writeValueAsString(new User(4,"赵六","男")); return s; //返回的data }else { return null; } }
RestFul风格
Restful风格是一种资源定位操作的风格,不是标准也不是协议,只是一种风格。基于这和风格设计可以更简洁,更有层次,更容易实现缓存等机制。
- 请求方式:使用POST,GET,PUT,DELETE等不同方法对资源进行操作。
- 分别对应:添加、查询、修改、删除
使用Restful风格可以通过不同的请求方式来实现不同的效果。请求地址栏一样,但功能不同!
- http://localhost:8080/item/1 查询,GET
- http://localhost:8080/item/ 新增,POST
- http://localhost:8080/item/ 更新,PUT
- http://localhost:8080/item/1 删除,DELETE
//@RequestMapping(value ="/test/{a}/{b}",method = RequestMethod.GET)
@GetMapping("/test/{a}/{b}")
public String allUser(@PathVariable int a , @PathVariable int b , Model md){
int res = a+b;
md.addAttribute("s",res);
return "test";
}
- controller形参列表处,每个形参前加上注解
@PathVariable
- Mapping注解在请求地址后加上参数
@GetMapping("/test/{a}/{b}")
- 选用不同请求可使用不同注解,也可在
@RequestMapping
注解中加入method = RequestMethod.GET
浏览器效果:http://localhost:8080/test/2/8
- 使用RestFul风格可使请求名复用(相同请求名使用不同请求方式)
- 可在地址栏隐藏参数名
SpringMVC拦截器
过滤器:
- servlet规范中的一部分,任何java web工程都可以使用
- 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
<!--乱码过滤器-->
<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>
拦截器:
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。拦截器是AOP思想的具体应用。
- 拦截器是SpringMVC自己的,只有使用了SpringMVC自己的工程才能使用。
- 拦截器只会拦截访问控制器的方法。如果访问jsp/html/css/image/js等静态资源是不会进行拦截的(减少资源损耗)。
实现拦截器
-
写一个类,实现
HandlerInterceptor
接口,可选重写三个方法public class MyInterceptor implements HandlerInterceptor { //return true;会放行,执行下一个拦截器/return false;会卡死,不执行下一个拦截器 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("处理前-------------------"); return true; } //拦截日志 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("处理后-------------------"); } //拦截日志 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("清理-------------------"); } }
-
因为使用了AOP所以必须在xml中配置。
<!--配置拦截器--> <mvc:interceptors> <mvc:interceptor> <!-- path:处理请求路径 /只拦截一个请求 /**拦截一个请求下的所有请求 --> <mvc:mapping path="/**"/> <bean class="com.sx.config.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>
文件上传
前端操作
- 在表单属性中加入
multipart/form-data
,这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
<form action="" enctype="multipart/form-data" method="post">
<input type="file" name="file">
<input type="submit" value="sub">
</form>
后端操作
springMVC对文件上传提供了专门的支持,这种支持是即插即用的MultipartResolver
实现的。
-
导入文件上传的jar包,commons-fileupload,Maven会自动帮我们导入他的依赖包。
<!--文件上传--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> <!--io包--> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <!--更高版本的servlet-api--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency>
-
在xml文件中配置
<!--文件上传配置--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!--编码格式必须和jsp的pageEncoding属性一致,以便正确读取表单内容--> <property name="defaultEncoding" value="utf-8"/> <!--上传限制大小,字节(10485760=10M)--> <property name="maxUploadSize" value="10485760"/> <property name="maxInMemorySize" value="40960"/> </bean>
-
controller
@RequestMapping("test") public String allUser(MultipartFile inFile) throws IOException { String filePath = "D:\"; //本地路径 if (!inFile.isEmpty()){ //文件是否为空 String originalFilename = inFile.getOriginalFilename(); //获取上传的文件名 originalFilename = UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf(".")); //避免名称相同,上传文件名改为UUID名+原文件名后缀 File file = new File(filePath, originalFilename); inFile.transferTo(file); } return "test"; }