SpringMVC

MVC三层架构
  • Controller层:取得前端数据、调用相关业务逻辑、转发/重定向到其他页面
  • Model层:实现业务逻辑、保存数据
  • View层:显示页面

1.第一个MVC程序

  • 新建一个web项目,导入相关依赖<spring-webmvc、javax.servlet-api、jsp-api、jstl>
  • 编写SpringMVC 的 配置文件,名称: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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>


  • 在web.xml中注册DispatcherServlet
  <!--1.注册DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个springmvc的配置文件:【servlet-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>


  • 在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"
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"/>

<!--视图解析器:DispatcherServlet给他的ModelAndView-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<!-- 因为我这里jsp路径并不需要前缀,所以省略了-->
<!-- <property name="prefix" value="/WEB-INF/jsp/"/>-->
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>


  • 编写一个Controller业务控制类(封装数据、定位视图)
public class MyTest implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();

//封装对象,放在ModelAndView中。Model
mv.addObject("msg","HelloSpringMVC!");
//封装要跳转的视图,放在ModelAndView中
mv.setViewName("test"); //: /WEB-INF/jsp/hello.jsp
return mv;
}
}


  • 在springmvc-servlet.xml中注册业务控制类
<bean id="/test" class="MyTest"></bean>


  • 编写跳转页面
<%--
Created by IntelliJ IDEA.
User: 姬如千泷
Date: 2021/7/24
Time: 6:58
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>


1.1 如果访问404的话可能是以下问题
  • 看控制台实际导入的jar包和导入的依赖包是否一致

SSM框架——SpringMVC_拦截器

  • 在tomcat的war包目录中加入lib依赖

SSM框架——SpringMVC_xml_02

  • 查看注册bean的id是否加 ' / ',因为这个id即为访问路径

2. SpringMVC框架的执行原理

SSM框架——SpringMVC_xml_03

  • DispatcherServlet核心接收前端的URL,并交付给处理器映射,将其映射成可识别的业务逻辑块(类),返回给D-Servlet
  • DispatcherServlet将返回的控制逻辑交付给控制适配器负责调用相关的业务逻辑,并将调用结果返回给D-Servlet
  • DispatcherServlet将业务逻辑的执行结果(ModelAndView)交给解析器解析成对应的数据和视图,显示到前端

3.注解开发MVC

  • 配置web.xml,注册DispatcherServlet,跟前面一样
  • 配置springmvc配置文件
<?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
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 base-package="com.kuang.controller"/>
<!-- 让Spring MVC不处理静态资源,否则静态资源也会进行解析,产生错误-->
<mvc:default-servlet-handler />
<!--
支持mvc注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系
要想使@RequestMapping注解生效
必须向上下文中注册DefaultAnnotationHandlerMapping
和一个AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理。
而annotation-driven配置帮助我们自动完成上述两个实例的注入。
-->
<mvc:annotation-driven />
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<!--<property name="prefix" value="/WEB-INF/jsp/" /> -->
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>

</beans>


  • 编写"控制类"Controller
@Controller
@RequestMapping("/XXX")//父路径,可以省略
public class HelloController {

@RequestMapping("/hello")//实际访问路径
public String sayHello(Model model){
//向模型中封装数据,可以在视图解析中渲染视图
model.addAttribute("msg","hello,SpringMVC");
return "hello";//映射的视图
}
//可以同时创建多个映射
}


  • 编写跳转视图

3.RestFul的URL风格

Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

3.1 使用@PathVariable实现RestFul风格
  @RequestMapping("/commit/{p1}/{p2}")
//参数的p1和p2会被自动映射到入口url处
public String index(@PathVariable int p1, @PathVariable int p2, Model model){
int result = p1+p2;
model.addAttribute("msg", "结果:"+result);
return "test";
}


4.结果转发和乱码处理

4.1 用ServletAPI 实现结果转发

通过将控制类的子映射函数的参数设定为request和response来定义结果重定向和转发,不需要注册视图解析器

  • 直接输出
@RequestMapping("/result/t1")
public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.getWriter().println("Hello,Spring BY servlet API");
}


  • 实现重定向
@RequestMapping("/result/t2")
public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.sendRedirect("/index.jsp");
}


  • 实现转发
 @RequestMapping("/result/t3")
public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
//转发
req.setAttribute("msg","/result/t3");
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);
}


4.2 通过SpringMVC实现结果转发

不需要视图解析器,如果有视图解析器,则只需要返回核心视图名

  • 实现转发①
@RequestMapping("/rsm/t1")
public String test1(){
//转发
return "/index.jsp";
}


  • 实现转发②
@RequestMapping("/rsm/t1")
public String test1(){
//转发
return "/index.jsp";
}


  • 实现重定向
 @RequestMapping("/rsm/t3")
public String test3(){
//重定向
return "redirect:/index.jsp";
}


4.3 乱码处理
4.3.1 springMVC自带的过滤器实现(大多数情况)
<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.3.2 tomcat配置文件修改(少数情况下)

apache-tomcat-9.0.46\conf\server.xml

<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />


5.Json

java层解析前端的Json对象需要使用解析器,而对应需要导入相关依赖(jackson、Fastjson等)

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>


5.1 将java对象封装成json对象返回给前端(jackson)
@Controller
public class UserController {
@RequestMapping("/json1")
@ResponseBody//该注释使该方法不会交给mvc解析
public String json1() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
User user = new User("秦疆1号", 3, "男");
//将我们的对象解析成为json格式
String str = mapper.writeValueAsString(user);
return str;
}
}


  • 可以直接将类用@RestController 注解注释,则指明该类下所有映射方法都不交由mvc解析
  • 当要传入时间对象时,json会默认转换成毫秒数格式,若要显示自定义格式的时间,则可以添加一个参数设置
@RequestMapping("/json4")
public String json4() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
//不使用时间戳的方式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//自定义日期格式对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//指定日期格式
mapper.setDateFormat(sdf);
Date date = new Date();
String str = mapper.writeValueAsString(date);
return str;
}


5.2 解决Json乱码问题
  • 在RequestMapping注解中加入参数
//produces:指定响应体返回类型和编码
@RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")


  • 使用mvc配置文件统一解决
<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>


5.3 将java对象封装成json对象返回给前端(Fastjson)
public class FastJsonDemo {
public static void main(String[] args) {
//创建一个对象
User user1 = new User("秦疆1号", 3, "男");
//一个对象数组,初始化省略
List<User> list = new ArrayList<User>();
//Java对象转JSON字符串
String str1 = JSON.toJSONString(list);
String str2 = JSON.toJSONString(user1);
//JSON字符串转Java对象
User user=JSON.parseObject(str2,User.class);
//Java对象转JSON对象
JSONObject jsonObject = (JSONObject) JSON.toJSON(user2);
//JSON对象转Java对象
User java_json = JSON.toJavaObject(jsonObject, User.class);
}
}


6.Ajax阿贾克斯

通过异步请求实现页面局部更新

6.1 通过jQuery实现ajax
  • 导入jQuery包
<!--在线CDN导入-->
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<!--本地项目包导入-->
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.1.1.min.js"></script>


  • 基本形式(post举例)
 $.post({
url:"${pageContext.request.contextPath}/a1",//请求提交的目的地url
data:{'name':$("#txtName").val()},//传递的数据
success:function (data,status) {//callback回调函数,接收后端服务返回的值
alert(data);
alert(status);
}
});


7. MVC拦截器

与servlet中的过滤器不同的是,拦截器是spring-mvc特有的工具,并且拦截器只会在访问控制方法时拦截,原理是Aop思想

  • 编写拦截器(可根据需要只重写部分方法)
public class MyInterceptor implements HandlerInterceptor {

public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("------------处理前------------");
//如果返回true执行下一个拦截器,如果返回false就不执行下一个拦截器
return true;
}

//在请求处理方法执行之后执行
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("------------处理后------------");
}
//在dispatcherServlet处理后执行,做清理工作.
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("------------清理------------");
}
}


  • 配置拦截器
<!--关于拦截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路径及其子路径-->
<mvc:mapping path="/**"/>
<!--bean配置的就是拦截器-->
<bean class="com.kuang.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>