0. 简介
本文用于记录本人的SpringMVC学习内容以及部分自己的理解,参考资料源自以下:
狂神说Java——SpringMVC
fastjson常用方法_authority39的博客-CSDN博客_fastjson常用方法
可能有部分理解不到位的地方,不喜勿喷。
1. Spring MVC与常规开发
常规开发流程
- 研究相关jsp文件和js文件(有可能有ajax请求)中是否发送了http请求,如果是,根据请求需要返回的数据做业务实现;
- 先从Dao层的代码开始编写,实现相应功能的部分返回值要求,也可能是全部,如添加功能只需要一个方法就可以实现,而用户管理功能需要搜索和分页多个功能,此时Dao层需要根据需求编写多个方法;
- 完成Dao层代码编写,接着开始完成Service层的代码,一般都是一些比较模板化的代码,但是在像动态搜索这种功能的实现中,可能需要判断传递过来的参数;
- 完成Service层代码编写,可以写控制层代码,即Servlet,根据功能实现的需求进行设置相应的参数,并选择使用重定向或者请求转发的方式将相应的参数返回,如果是ajax请求则是json格式的数据,另外,在ajax中重定向和请求转发的代码是不会生效的;
- 注册Servlet,运行查看代码效果,如果有bug就debug,没有就进行下一个模块的开发;
使用Spring MVC的开发:
- 只需要注册一个DispatcherServlet,而不需要反复去注册Servlet;
- 通过添加@Controller标签实现控制器的编写,同时可以在一个Controller中编写多个不同url请求,极大地简化了反复自定义Servlet类的过程;
- 可以实现GET,POST等方法;
2. SpringMVC的特点:
- RESTful风格,支持数据验证
- 简洁灵活
3. SpringMVC的执行流程
-
确定导入了SpringMVC的相关包
-
配置web.xml,注册DispatcherServlet
<servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--关联一个springmvc的配置文件--> <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> <servlet-mapping> <!-- / :匹配所有的请求,不包括jsp /*:匹配所有的请求,包括jsp --> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
-
设置springmvc-servlet.xml配置文件:
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <!--设置处理器映射器--> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /> <!--设置处理器适配器--> <bean clss="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> <!--跳转视图前缀--> <property name="prefix" value="/WEB-INF/jsp/" /> <!--跳转试图后缀--> <property name="suffix" value=".jsp" /> </bean> <!--设置视图解析器-->
-
编写相关控制器代码:
public class HelloController implements Controller{ //重写方法 public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)throws Exception{ ModelAndView modelAndView= new ModelAndView(); //封装信息,放在ModelAndView中 modelAndView.addObject("msg","HelloSpringMVC"); //设置跳转视图 modelAndView.setViewName("hello"); //返回给视图解析器 return modelAndView; } }
-
将写好的控制器类配置到springmvc-servlet.xml中
<bean id="/hello" class="xxx.xxx.xxx.HelloController" />
-
工作流程:启动Tomcat后,因为设置了DispatcherServlet收到所有带 “/” 前缀的请求,所以请求发给了DispatcherServlet,DispatcherServlet再发给处理器映射器,经过处理后发回给DispatcherServlet,然后DispatcherServlet再发给处理器适配器,发现匹配上了springmvc-servlet.xml中的id为 “/hello” 的bean,于是执行其中重写的handleRequest()方法,返回一个ModelAndView,由DispatcherServlet转交给视图解析器,同时携带信息msg以及要跳转到的视图 “hello” ,由视图解析器加上前后缀,拿到资源/WEB-INF/jsp/hello.jsp,同时将携带的信息传递给jsp,渲染完成后返回给DispatcherServlet再返回给前端。(看狂神的图是这样的)
-
可能存在的问题:缺少JAR包,需要在IDEA的项目中导入。(添加lib目录导入所有需求包)
-
SpringMVC执行流程(查资料版):DispatcherServlet执行流程_wzs535131的博客-CSDN博客
- 用户发送请求给前端控制器DispatcherServlet;
- DispatcherServlet收到请求调用HandlerMapping处理器映射器;
- 处理器映射器找到具体的处理器(一般通过注解),生成处理器对象及处理器拦截器(如果有的话)并一起返回给DispatcherServlet;
- DispatcherServlet调用HandlerAdapter处理器适配器;
- HandlerAdapter经过适配调用具体的处理器(即Controller);
- Controller执行完成后返回ModelAndView;
- HandlerAdapter将controller执行结果ModelAndView传给DispatcherServlet;
- DispatcherServlet将ModelAndView传给视图解析器;
- ViewReslover解析后返回具体View;
- DispatcherServlet根据View进行渲染视图(数据填充);
- DispatcherServlet响应用户。
4. SpringMVC注解实现:
-
在web.xml中配置DispatcherServlet,这一点仍旧不变;
-
配置DispatchherServlet的配置文件,改动如下:
<beans xmlns="……………………………………" xmlns:xsi="……………………………………" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="…………………………………… http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--自动扫描包,让指定包下的注解生效,由IOC容器统一管理--> <context:component-scan bean-package="xxx.xxx.xxx" /> <!--让SpringMVC不处理静态资源 .css .html .js--> <mvc:default-servlet-handler /> <!--支持mvc注解驱动--> <mvc:annotation-driven /> …………………………………… <!--配置视图解析器--> </beans>
-
编写Controller层
@Controller //表示这是一个Controller //这里也可以给类添加注解@RequestMapping("/HelloController") //这样的话只有"localhost:8080/HelloController"的请求才能到达这个Controller public class HelloController{ @RequestMapping("/hello") //url映射地址 public String hello(Model model){ model.addAttribute("msg","Hello,SpringMVCAnnotation!"); return "hello"; //返回给视图解析器的内容,即目标jsp文件名 } }
-
如果想要使用重定向或者转发,需要将视图解析器注销掉,在return的时候,默认是实现转发,也可以加上关键字 “forward” 或者 “redirect” 实现转发和重定向:
return "redirect:WEB-INF/jsp/index.jsp"; return "forward:WEB-INF/jsp/index.jsp"; //但是这种情况下需要写上全名,因为没有了视图解析器
-
实现前后端的参数传递:
@RequestMapping("/add") public String add(@RequestParam("numFir")int a,@RequestParam("numSec")int b){ …………………………………… return "add"; }
通过这种方式,前端在访问 “localhost:8080/add?numFir=1&numSec=2” 的情况下就会跳转到该方法下执行相关操作。在这里,注解 “@RequestParam(”……")" 起到的作用是绑定前端传过来的参数。如果是使用自定义类来接收参数,则需要保证自定义类中的属性字段名与参数名一致,否则会出现异常。
5. RestFul风格编程:
-
针对于传统url访问下,泄露传递参数名的情况,RestFul风格编程可以有效保护信息:
localhost:8080/index?method=add&num1=1&num2=2 (传统编程风格下的访问方式)
localhost:8080/index/add/1/2 (Restful编程风格下的访问方式)
-
可以使用POST,DELETE,PUT,GET,不同的方法对相同资源进行操作,获得不同的结果;
-
实现前后端分离:返回给前端以JSON的形式的数据
-
当类注解为@Controller时,在相应的方法上添加注解@ResponseBody,这样子return的结果就不会走视图解析器,而是直接返回给前端的String结果;
-
当类注解为@RestController,该类中的所有方法的返回值都会直接给到前端,而不会走视图解析器;
-
使用jackson返回Json格式数据:
-
导入jackson相关的依赖:
<dependency> <gorupId>com.fasterxml.jackson.core</gorupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency>
-
使用方法:
ObjectMapper mapper = new ObjectMapper(); Object object = new Object(); //这里模拟的只是获取前端所需要参数的过程 //假设object是目标对象 String str = mapper.writeValueAsString(object); return str; //通过这种方式返回的String字符串其实会出现中文乱码的情况 //可以在Spring中配置一个处理器解决这个问题 //重复性的代码可以写成工具类实现复用 //对于时间戳对象的处理 Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); sdf.format(date);//这个方法的返回值类型是String //也可以采用设置ObjectMapper的format方法实现 mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false); mapper.setDateFormat(sdf);
-
解决Json中文乱码问题:
<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>
-
-
使用alibaba的Fastjson包返回Json格式数据:
-
导入fastjson的相关依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.66</version> </dependency>
-
常用方法:
//直接解析为对象: T t = JSON.parseObject(jsonstr,T,class); List<T> list = JSON.parseArray(jsonstr,T.class); //解析为JSON对象: Object obj = JSON.parse(jsonstr); JSONObject objJSON = JSON.parseObject(jsonstr); JSONArray arrJSON = JSON.parseArray(jsonstr); //获取JSONArray对象中的数据: JSONObject objJSON = arrJSON.get(i); T t = arrJSON.getObject(i,T.class); //获取JSONObject对象中的数据: Integer integer = objJSON.getInteger(key); String string = objJSON.getString(key); JOSNObject tar = objJSON.getJSONObject(key); JSONArray arrJSON = objJSON.getJSONArray(key); //格式化对象为json字符串 JSON.toJSONString(object); //上面的方法虽然看可以达成目标,但仍然存在部分问题,推荐使用以下方式: SerializerFeature quotefieldnames = SerializerFeature.QuoteFieldNames; // 输出的结果不带双引号 SerializerFeature writemapnullvalue = SerializerFeature.WriteMapNullValue; // 打印出null值的字段 SerializerFeature writenullstringasempty = SerializerFeature.WriteNullStringAsEmpty; // null值字段显示为"" SerializerFeature writenulllistasempty = SerializerFeature.WriteNullListAsEmpty; // null值数组显示为[] JSON.toJSONString(obj, quotefieldnames, writemapnullvalue, writenullstringasempty, writenulllistasempty); //可以将这部分代码封装实现复用
-
-
-
使用方式:
-
需要在相关方法中的参数上添加注解"@PathVariable",并修改相应的@RequestMapping
@Controller public class RestFulController{ @RequestMapping(path="/add/{a}/{b}") public String add(@PathVariable int a,@PathVariable int b,Model model){ …………………………………… return "add"; } }
-
实现多方法响应需要在RequestMapping中新增属性method,或者使用组合注解
@RequestMapping(path="……",method=RequestMethod.GET) @GetMapping("path值")
-
6. 乱码问题解决:注册过滤器(可以使用Spring自带的)
<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>