1.回顾MVC

1.1什么是MVC

  • MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。

  • 是将业务逻辑、数据、显示分离的方法来组织代码。

  • MVC主要作用是降低了视图与业务逻辑间的双向偶合。

  • MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。

Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。

View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。

Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。

最典型的MVC就是JSP + servlet + javabean的模式。

1.2Model1时代

  • 在web早期的开发中,通常采用的都是Model1。

  • Model1中,主要分为两层,视图层和模型层。

Model1优点:架构简单,比较适合小型项目开发;

Model1缺点:JSP职责不单一,职责过重,不便于维护;

1.3Model2时代

Model2把一个项目分成三部分,包括视图、控制、模型。

  • 用户发请求

  • Servlet接收请求数据,并调用对应的业务逻辑方法

  • 业务处理完毕,返回更新后的数据给servlet

  • servlet转向到JSP,由JSP来渲染页面

  • 响应给前端更新后的页面

职责分析:

Controller:控制器

  • 取得表单数据

  • 调用业务逻辑

  • 转向指定的页面

Model:模型

  • 业务逻辑

  • 保存数据的状态

View:视图

  • 显示页面

Model2这样不仅提高的代码的复用率与项目的扩展性,且大大降低了项目的维护成本。Model 1模式的实现比较简单,适用于快速开发小规模项目,Model1中JSP页面身兼View和Controller两种角色,将控制逻辑和表现逻辑混杂在一起,从而导致代码的重用性非常低,增加了应用的扩展性和维护的难度。Model2消除了Model1的缺点。

1.4回顾Servlet

1.4.1新建Maven导入依赖

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.22</version>
</dependency> <dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>

1.4.2 建子项目

为子项目添加Web

1.4.3 编写一个Servlet类

public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取前端参数
String method = req.getParameter("method");
if(method.equals("add")){
req.getSession().setAttribute("msg","执行了add方法");
}
if(method.equals("delete")){
req.getSession().setAttribute("msg","执行了delete方法"); }
//2.调用业务层 //3.视图转发或者重定向
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,resp);
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}

1.4.4 编写Hello.jsp

在WEB-INF目录下新建一个jsp的文件夹,新建test.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Kuangshen</title>
</head>
<body>
${msg}
</body>
</html>

1.4.5 web.xml中注册Servlet

<?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>hello</servlet-name>
<servlet-class>com.tang.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping> </web-app>

1.4.5编写form.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/hello" method="post">
<input type="text" name="method">
<input type="submit" name="method">
</form>
</body>
</html>

1.4.6配置Tomcat,并启动测试

*http://localhost:8080/SpringMVC_01_servlet_war_exploded/hello?method=delete

1.5MVC框架要做的事情

  • 将url映射到java类或java类的方法 .

  • 封装用户提交的数据 .

  • 处理请求--调用相关的业务处理--封装响应数据 .

  • 将响应的数据进行渲染 . jsp / html 等表示层数据

说明:

常见的服务器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF;常见前端MVC框架:vue、angularjs、react、backbone;由MVC演化出了另外一些模式如:MVP、MVVM 等等....

2.什么是SpringMVC

2.1、概述

Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。

查看官方文档:https://docs.spring.io/spring-framework/docs/4.3.24.RELEASE/spring-framework-reference/html/

我们为什么要学习SpringMVC呢?

Spring MVC的特点:

  • 轻量级,简单易学

  • 高效 , 基于请求响应的MVC框架

  • 与Spring兼容性好,无缝结合

  • 约定优于配置

  • 功能强大:RESTful、数据验证、格式化、本地化、主题等

  • 简洁灵活

Spring的web框架围绕DispatcherServlet [ 调度Servlet ] 设计。

DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解形式进行开发,十分简洁;

正因为SpringMVC好 , 简单 , 便捷 , 易学 , 天生和Spring无缝集成(使用SpringIoC和Aop) , 使用约定优于配置 . 能够进行简单的junit测试 . 支持Restful风格 .异常处理 , 本地化 , 国际化 , 数据验证 , 类型转换 , 拦截器 等等......所以我们要学习 .

最重要的一点还是用的人多 , 使用的公司多 .

2.2、中心控制器

Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式。

Spring MVC框架像许多其他MVC框架一样, 以请求为驱动 , 围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)。

SpringMVC的原理如下图所示:

当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者。

2.3、SpringMVC执行原理



图为SpringMVC的一个较完整的流程图,实线表示SpringMVC框架提供的技术,不需要开发者实现,虚线表示需要开发者实现。

简要分析执行流程

  • DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户 发出请求,DispatcherServlet接收请求并拦截请求。

    我们假设请求的url为 : http://localhost:8080/SpringMVC/hello

    如上url拆分成三部分:

    http://localhost:8080服务器域名

    SpringMVC部署在服务器上的web站点

    hello表示控制器

    通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。

  • HandlerMapping为处理器映射。DispatcherServlet调用 HandlerMapping,HandlerMapping根据请求url查找Handler。

  • HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。

  • HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。

  • HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。

  • Handler让具体的Controller执行。

  • Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。

  • HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。

  • DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。

  • 视图解析器将解析的逻辑视图名传给DispatcherServlet。

  • DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。

  • 最终视图呈现给用户。

在这里先听一遍原理,不理解没有关系,我们马上来写一个对应的代码实现大家就明白了,如果不明白,那就写10遍,没有笨人,只有懒人!

3.第一个MVC程序

3.1、配置版

  • 新建一个Moudle ,SpringMVC-02-hellomvc , 添加web的支持!

  • 确定导入了SpringMVC 的依赖!

  • 配置web.xml , 注册DispatcherServlet

<?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"> <!--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>
</web-app>
  • 编写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>
  • 在springmvc-servlet.xml 添加 处理映射器
<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">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
  • 编写我们要操作业务Controller ,要么实现Controller接口,要么增加注解;需要返回一个ModelAndView,装数据,封视图;
//注意:这里我们先导入Controller接口
public class HelloController 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("hello"); //: /WEB-INF/jsp/hello.jsp
return mv;
}
}
  • 将自己的类交给SpringIOC容器,注册bean
<!--Handler-->
<bean id="/hello" class="com.kuang.controller.HelloController"/>
  • 写要跳转的jsp页面,显示ModelandView存放的数据,以及我们的正常页面;
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body> ${msg}
</body>
</html>
  • 配置Tomcat 启动测试!

可能遇到的问题:访问出现404,排查步骤:

  • 查看控制台输出,看一下是不是缺少了什么jar包。

  • 如果jar包存在,显示无法输出,就在IDEA的项目发布中,添加lib依赖!

  • 重启Tomcat 即可解决!

小结:看这个估计大部分同学都能理解其中的原理了,但是我们实际开发才不会这么写,不然就疯了,还学这个玩意干嘛!我们来看个注解版实现,这才是SpringMVC的精髓,到底有多么简单,看这个图就知道了

3.2、注解版

  • 新建一个Moudle,SpringMVC-03-annotation 。添加web支持!

  • 由于Maven可能存在资源过滤的问题,我们将配置完善

  • 配置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"> <!--1.注册servlet-->
    <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>
    <!-- 启动顺序,数字越小,启动越早 -->
    <load-on-startup>1</load-on-startup>
    </servlet> <!--所有请求都会被springmvc拦截 -->
    <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping> </web-app>
  • 添加Spring MVC配置文件


    <?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.tang.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

    编写一个Java控制类:com.kuang.controller.HelloController , 注意编码规范

    @Controller
    public class HelloController { //真实访问地址 : 项目名/h1
    @RequestMapping("/h1")
    public String sayHello(Model model){
    //向模型中添加属性msg与值,可以在JSP页面中取出并渲染
    model.addAttribute("msg","hello,SpringMVC");
    //web-inf/jsp/hello.jsp
    return "hello";
    }
    }
    • @Controller是为了让Spring IOC容器初始化时自动扫描到;

    • @RequestMapping是为了映射请求路径,这里因为类与方法上都有映射所以访问时应该是/HelloController/hello;

  • 方法中声明Model类型的参数是为了把Action中的数据带到视图中;

  • 方法返回的结果是视图的名称hello,加上配置文件中的前后缀变成WEB-INF/jsp/hello.jsp。

创建视图层

在WEB-INF/ jsp目录中创建hello.jsp , 视图可以直接取出并展示从Controller带回的信息;

可以通过EL表示取出Model中存放的值,或者对象;


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>SpringMVC</title>
</head>
<body>
${msg}
</body>
</html>

测试结果图

  • 小结

    • 实现步骤其实非常的简单:

    • 新建一个web项目

    • 导入相关jar包

    • 编写web.xml , 注册DispatcherServlet

    • 编写springmvc配置文件

    • 接下来就是去创建对应的控制类 , controller

    • 最后完善前端视图和controller之间的对应

    测试运行调试.

    使用springMVC必须配置的三大件:

    处理器映射器、处理器适配器、视图解析器

    通常,我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可,而省去了大段的xml配置

4.控制器controller

  • 控制器复杂提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现。

  • 控制器负责解析用户的请求并将其转换为一个模型。

  • 在Spring MVC中一个控制器类可以包含多个方法

  • 在Spring MVC中,对于Controller的配置方式有很多种

4.1实现Controller接口

Controller是一个接口,在org.springframework.web.servlet.mvc包下,接口中只有一个方法;
测试

  1. 新建一个Moudle,SpringMVC-04-controller 。将刚才的03 拷贝一份, 我们进行操作!
  • 删掉HelloController

  • mvc的配置文件只留下 视图解析器!

编写一个Controller类,ControllerTest1

public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView(); mv.addObject("msg","ControllerTest1");
mv.setViewName("test"); return mv;
}
}
  1. 编写完毕后,去Spring配置文件中注册请求的bean;name对应请求路径,class对应处理请求的类
<bean name="/t1" class="com.tang.controlller.ControllerTest1"></bean>
  1. 编写前端test.jsp,注意在WEB-INF/jsp目录下编写,对应我们的视图解析器
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>

配置Tomcat运行测试,我这里没有项目发布名配置的就是一个 / ,所以请求不用加项目名,OK!

4.2使用注解@Controller

  • @Controller注解类型用于声明Spring类的实例是一个控制器(在讲IOC时还提到了另外3个注解);

  • Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描。

<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="com.tang.controller"/>
  • 增加一个ControllerTest2类,使用注解实现;
@Controller
public class ControllerTest2 {
//映射访问路径
@RequestMapping("/t2")
public String test(Model model){
//Spring MVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg","ControllerTest2");
//返回视图位置
return "test";
}
}

运行tomcat测试



可以发现,我们的两个请求都可以指向一个视图,但是页面结果的结果是不一样的,从这里可以看出视图是被复用的,而控制器与视图之间是弱偶合关系。

注解方式是平时使用的最多的方式!

4.3RestFul风格

概念

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

功能

资源:互联网所有的事物都可以被抽象为资源

资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。

分别对应 添加、 删除、修改、查询。

传统方式操作资源 :通过不同的参数来实现不同的效果!方法单一,post 和 get

http://127.0.0.1/item/queryItem.action?id=1 查询,GET

http://127.0.0.1/item/saveItem.action 新增,POST

http://127.0.0.1/item/updateItem.action 更新,POST

http://127.0.0.1/item/deleteItem.action?id=1 删除,GET或POST

使用RESTful操作资源 :可以通过不同的请求方式来实现不同的效果!如下:请求地址一样,但是功能可以不同!

http://127.0.0.1/item/1 查询,GET

http://127.0.0.1/item 新增,POST

http://127.0.0.1/item 更新,PUT

http://127.0.0.1/item/1 删除,DELETE

学习测试

在新建一个类 RestFulController

4.4结果跳转方式

通过SpringMVC来实现转发和重定向 - 无需视图解析器;

测试前,需要将视图解析器注释掉

@Controller
public class ResultSpringMVC {
@RequestMapping("/rsm/t1")
public String test1(){
//转发
return "/index.jsp";
} @RequestMapping("/rsm/t2")
public String test2(){
//转发二
return "forward:/index.jsp";
} @RequestMapping("/rsm/t3")
public String test3(){
//重定向
return "redirect:/index.jsp";
}
}

通过SpringMVC来实现转发和重定向 - 有视图解析器;

重定向 , 不需要视图解析器 , 本质就是重新请求一个新地方嘛 , 所以注意路径问题.

可以重定向到另外一个请求实现 .

@Controller
public class ResultSpringMVC2 {
@RequestMapping("/rsm2/t1")
public String test1(){
//转发
return "test";
} @RequestMapping("/rsm2/t2")
public String test2(){
//重定向
return "redirect:/index.jsp";
//return "redirect:hello.do"; //hello.do为另一个请求/
} }

4.5数据处理

处理提交数据

4.5.1提交的域名称和处理方法的参数名一致

提交数据 : http://localhost:8080/SpringMVC_04_controller_war_exploded/user/t1?name=Twq

处理方法 :

@RequestMapping("/user")
public class UserController { @GetMapping("/t1")
public String test1(String name,Model model){ //1.接收前端参数
System.out.println("接收到的前端的参数为:" +name); //2.返回的结果传递给前端
model.addAttribute("msg",name); //3.视图跳转
return "test";
} }

4.5.2提交的域名称和处理方法的参数名不一致

4.5.3提交的域名称和处理方法的参数名不一致

@Controller
@RequestMapping("/user")
public class UserController { @GetMapping("/t1")
public String test1(@RequestParam("username") String name, Model model){ //1.接收前端参数
System.out.println("接收到的前端的参数为:" +name); //2.返回的结果传递给前端
model.addAttribute("msg",name); //3.视图跳转
return "test";
} }

4.5.4提交的是一个对象

要求提交的表单域和对象的属性名一致 , 参数使用对象即可

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private int age;
}

测试代码

//前端接受的是一个对象:id,name,age

  /*
1.接收前端用户传的参数,判断参数的名字,假设名字直接在方法上,可以直接使用
2.假设出阿尼的是一个对象User,匹配User对象中的字段名:如果名字一致则OK,否则,匹配不到 */
@GetMapping("/t2")
public String test2(User user){
System.out.println(user);
return "test";
}

4.6乱码问题解决

@Controller
public class EncodingController {
@PostMapping("e1/t1")
public String test(String name,Model model){ model.addAttribute("msg",name);
return "test";
}
}

提交界面

<body>

<form action="e1/t1" method="post">
用户名 <input type="text" name="name">
<input type="submit">
</form>
</body>

测试结果



解决方法

在web.xml中配置SpringMVC的乱码的过滤

<!--配置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>

在启动Tomcat测试



如果以上方法还是解决不了,可以自定义以下过滤器,以下代码建议全部复制,如果让IDEA自动导包的话可能会倒错包,以下代码为网上大牛写的,实在不行的情况下建议使用

package com.tang.filter;//这一行除外,根据自己的包名写

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map; /**
* 解决get和post请求 全部乱码的过滤器
*/
public class GenericEncodingFilter implements Filter { public void destroy() {
} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//处理response的字符编码
HttpServletResponse myResponse=(HttpServletResponse) response;
myResponse.setContentType("text/html;charset=UTF-8"); // 转型为与协议相关对象
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 对request包装增强
HttpServletRequest myrequest = new MyRequest(httpServletRequest);
chain.doFilter(myrequest, response);
} public void init(FilterConfig filterConfig) throws ServletException {
} } //自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper { private HttpServletRequest request;
//是否编码的标记
private boolean hasEncode;
//定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
public MyRequest(HttpServletRequest request) {
super(request);// super必须写
this.request = request;
} // 对需要增强方法 进行覆盖
@Override
public Map getParameterMap() {
// 先获得请求方式
String method = request.getMethod();
if (method.equalsIgnoreCase("post")) {
// post请求
try {
// 处理post乱码
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (method.equalsIgnoreCase("get")) {
// get请求
Map<String, String[]> parameterMap = request.getParameterMap();
if (!hasEncode) { // 确保get手动编码逻辑只运行一次
for (String parameterName : parameterMap.keySet()) {
String[] values = parameterMap.get(parameterName);
if (values != null) {
for (int i = 0; i < values.length; i++) {
try {
// 处理get乱码
values[i] = new String(values[i]
.getBytes("ISO-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
hasEncode = true;
}
return parameterMap;
}
return super.getParameterMap();
} //取一个值
@Override
public String getParameter(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
if (values == null) {
return null;
}
return values[0]; // 取回参数的第一个值
} //取所有值
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
return values;
}
}

web.xml注册该过滤器

<filter>
<filter-name>encoding</filter-name>
<filter-class>com.tang.filter.GenericEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

6.JSON

6.1什么是JSON

  • JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别广泛。

  • 采用完全独立于编程语言的文本格式来存储和表示数据。

  • 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。

  • 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

在 JavaScript 语言中,一切都是对象。因此,任何JavaScript 支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。看看他的要求和语法格式:

  • 对象表示为键值对,数据由逗号分隔

  • 花括号保存对象

  • 方括号保存数组

JSON 键值对是用来保存 JavaScript 对象的一种方式,和 JavaScript 对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号 "" 包裹,使用冒号 : 分隔,然后紧接着值:

{"name": "QinJiang"}
{"age": "3"}
{"sex": "男"}

很多人搞不清楚 JSON 和 JavaScript 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:

JSON 是 JavaScript 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。

var obj = {a: 'Hello',
b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹的 var json = '{"a": "Hello",
"b": "World"}'; //这是一个 JSON 字符串,本质是一个字符串

JSON 和 JavaScript 对象互转

要实现从JSON字符串转换为JavaScript 对象,使用 JSON.parse() 方法:

var obj = JSON.parse('{"a": "Hello", "b": "World"}');
//结果是 {a: 'Hello', b: 'World'}

要实现从JavaScript 对象转换为JSON字符串,使用 JSON.stringify() 方法:

var json = JSON.stringify({a: 'Hello', b: 'World'});
//结果是 '{"a": "Hello", "b": "World"}'

代码测试

  • 新建一个module ,springmvc-05-json , 添加web的支持

  • 在web目录下新建一个 json-1.html , 编写测试内容

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSON</title>
</head>
<body> <script type="text/javascript">
//编写一个js的对象
var user = {
name:"唐昊",
age:21,
sex:"男"
};
//将js对象转换成json字符串
var str = JSON.stringify(user);
console.log(str); //将json字符串转换为js对象
var user2 = JSON.parse(str);
console.log(user2.age,user2.name,user2.sex); </script> </body>
</html>

6.2Jackson使用

Jackson应该是目前比较好的json解析工具了

当然工具不止这一个,比如还有阿里巴巴的 fastjson 等等。

我们这里使用Jackson,使用它需要导入它的jar包;

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>

配置SpringMVC需要的配置

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"> <!--1.注册servlet-->
<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>
<!-- 启动顺序,数字越小,启动越早 -->
<load-on-startup>1</load-on-startup>
</servlet> <!--所有请求都会被springmvc拦截 -->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> <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> </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: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.tang.controller"/> <context:annotation-config />
<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>

这里我们需要两个新东西,一个是@ResponseBody,一个是ObjectMapper对象,我们看下具体的用法

编写一个Controller;

package com.tang.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tang.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; @Controller
public class UserController {
@RequestMapping("/j1")
@ResponseBody
public String test() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); User user = new User("唐三", 2, "女"); String str = mapper.writeValueAsString(user);
return str;
}
}

实体类

package com.tang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor; @Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
private String sex;
}

发现出现了乱码问题,我们需要设置一下他的编码格式为utf-8,以及它返回的类型;

通过@RequestMaping的produces属性来实现,修改下代码

//produces:指定响应体返回类型和编码
@RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")

再次测试发现乱码问题解决

乱码统一解决

上一种方法比较麻烦,如果项目中有许多请求则每一个都要添加,可以通过Spring配置统一指定,这样就不用每次都去处理了!

我们可以在springmvc的配置文件上添加一段消息StringHttpMessageConverter转换配置!

<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字符串统一解决

在类上直接使用 @RestController ,这样子,里面所有的方法都只会返回 json 字符串了,不用再每一个都添加@ResponseBody !我们在前后端分离开发中,一般都使用 @RestController ,十分便捷!

@RestController
public class UserController { //produces:指定响应体返回类型和编码
@RequestMapping(value = "/json1")
public String json1() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
//创建一个对象
User user = new User("秦疆1号", 3, "男");
//将我们的对象解析成为json格式
String str = mapper.writeValueAsString(user);
//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
return str;
} }

6.3fastjson

fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象的转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。实现json的转换方法很多,最后的实现结果都是一样的。

fastjson 的 pom依赖!

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>

fastjson 三个主要的类:

  • JSONObject 代表 json 对象

    • JSONObject实现了Map接口, 猜想 JSONObject底层操作是由Map实现的。

    • JSONObject对应json对象,通过各种形式的get()方法可以获取json对象中的数据,也可利用诸如size(),isEmpty()等方法获取"键:值"对的个数和判断是否为空。其本质是通过实现Map接口并调用接口中的方法完成的。

  • JSONArray 代表 json 对象数组

    • 内部是有List接口中的方法来完成操作的。
  • JSON代表 JSONObject和JSONArray的转化

    • JSON类源码分析与使用

    • 仔细观察这些方法,主要是实现json对象,json对象数组,javabean对象,json字符串之间的相互转化。

package com.tang.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kuang.pojo.User; import java.util.ArrayList;
import java.util.List; public class FastJsonDemo {
public static void main(String[] args) {
//创建一个对象
User user1 = new User("唐昊1号", 3, "男");
User user2 = new User("唐昊2号", 3, "男");
User user3 = new User("唐昊3号", 3, "男");
User user4 = new User("唐昊4号", 3, "男");
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4); System.out.println("*******Java对象 转 JSON字符串*******");
String str1 = JSON.toJSONString(list);
System.out.println("JSON.toJSONString(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("JSON.parseObject(str2,User.class)==>"+jp_user1); System.out.println("\n****** Java对象 转 JSON对象 ******");
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
System.out.println("(JSONObject) JSON.toJSON(user2)==>"+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);
}
}

7.SSM整合

导入依赖

<?xml version="1.0" encoding="UTF-8" ?>

<!--maven的版本和头文件-->
<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">
<modelVersion>4.0.0</modelVersion> <groupId>org.example </groupId>
<artifactId>SSMBuild</artifactId>
<version>1.0-SNAPSHOT</version> <!-- 建立父子关系时,父类的打包方式必须是pom,而且必须声明-->
<packaging>pom</packaging>
<dependencies>
<!--Junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency> <!--Servlet - JSP -->
<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>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency> <!--Mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency> <!--Spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.22</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.22</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</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>

7.1Mybatis层

项目结构图

7.1.1编写db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai jdbc.username=root
jdbc.password=root123456

7.1.2IDEA关联数据库

7.1.3编写MyBatis的核心配置文件

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.tang.pojo"/>
</typeAliases> <mappers>
<mapper class="com.tang.dao.BookMapper"/>
</mappers>
</configuration>

7.1.4.编写实体类

Books

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Books { private int bookID;
private String bookName;
private int bookCounts;
private String detail; }

7.1.5编写Dao层的 Mapper接口!

public interface BookMapper {

    //增加一本书
int addBook(Books books); //删除一本书
int deleteBookById(@Param("bookId") int id); //更新一本书
int updateBook(Books books); //查询一本书
Books queryBookById(@Param("bookId") int id); //查询全部的书
List<Books> queryAllBook();
}

7.1.6编写接口对应的 Mapper.xml 文件

需要导入MyBatis的包;
BookMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tang.dao.BookMapper">
<!--增加一本Book-->
<insert id="addBook" parameterType="Books">
insert into ssmbuild.books (bookName,bookCounts,detail)
values (#{bookName},#{bookCounts},#{detail})
</insert> <!--根据id删除一本Book-->
<delete id="deleteBookById" parameterType="int">
delete from ssmbuild.books where bookID=#{bookId}
</delete> <!--更新Book-->
<update id="updateBook" parameterType="Books">
update ssmbuild.books
set bookName=#{bookName},bookCounts=#{bookCounts},detail=#{detail}
where bookID=#{bookID}
</update> <!--根据id查询,返回一本Book-->
<select id="queryBookById" resultType="Books">
select * from books
where bookID=#{bookId}
</select> <!--查询全部Book-->
<select id="queryAllBook" resultType="Books">
select * from books
</select>
</mapper>

7.1.7编写Service层的接口和实现类

接口
public interface BookService {
//增加一本书
int addBook(Books books); //删除一本书
int deleteBookById( int id); //更新一本书
int updateBook(Books books); //查询一本书
Books queryBookById(int id); //查询全部的书
List<Books> queryAllBook();
}
实现类
package com.tang.service;

import com.tang.dao.BookMapper;
import com.tang.pojo.Books; import java.util.List; public class BookServiceImpl implements BookService{
//service调dao层,组合Dao
private BookMapper bookMapper;
public void setBookMapper(BookMapper bookMapper){
this.bookMapper = bookMapper;
} public int addBook(Books books) {
return bookMapper.addBook(books);
} public int deleteBookById(int id) {
return bookMapper.deleteBookById(id);
} public int updateBook(Books books) {
return bookMapper.updateBook(books);
} public Books queryBookById(int id) {
return bookMapper.queryBookById(id);
} public List<Books> queryAllBook() {
return bookMapper.queryAllBook();
}
}

OK,到此,底层需求操作编写完毕!

7.2Spring层

7.2.1配置Spring整合MyBatis

我们这里数据源使用c3p0连接池;

7.2.2编写Spring整合Mybatis的配置文件

7.2.3spring整合dao层

spring-dao.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: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
https://www.springframework.org/schema/context/spring-context.xsd"> <!--1.关联数据库配置文件-->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder> <!--2.连接池-->
<!--数据库连接池
dbcp 半自动化操作 不能自动连接
c3p0 自动化操作(自动的加载配置文件 并且设置到对象里面)
-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/> <!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false"/>
<!-- 获取连接超时时间 ms-->
<property name="checkoutTimeout" value="10000"/>
<!-- 当获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2"/>
</bean> <!-- 3.配置SqlSessionFactory对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean> <!--配置dao接口扫描包,动态的实现了Dao接口可以注入到Spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!--要扫描的dao包-->
<property name="basePackage" value="com.tang.dao"/>
</bean>
</beans>

7.2.4Spring整合service层

<?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"
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"> <!--1. 扫描service相关的bean -->
<context:component-scan base-package="com.tang.service" /> <!--2.BookServiceImpl注入到IOC容器中-->
<bean id="BookServiceImpl" class="com.tang.service.BookServiceImpl">
<!--service层要和dao层联系起来,除了IDEA自动帮我们做的之外,
还可以在service层通过import来导入spring-dao.xml使得service层和dao层关联起来-->
<property name="bookMapper" ref="bookMapper"/>
</bean> <!--3.配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource" />
</bean> </beans>

7.3SpringMVC层

7.3.1web.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"> <!--DispatchServlet-->
<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:spring-mvc.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>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> <!--Session-->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
</web-app>

7.3.2spring-mvc.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"
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
https://www.springframework.org/schema/context/spring-context.xsd">
<!--1.注解驱动-->
<mvc:annotation-driven/> <!--2.静态资源过滤-->
<mvc:default-servlet-handler/> <!--3.扫描包:controller-->
<context:component-scan base-package="com.tang.controller"/> <!--4.视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp"/>
<property name="suffix" value=".jsp"/>
</bean> </beans>

7.3.3applicationContext.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"> <import resource="classpath:spring-dao.xml"/>
<import resource="classpath:spring-service.xml"/>
<import resource="classpath:spring-mvc.xml"/> </beans>

7.4查询书籍功能

7.4.1 BookController类编写

方法一:查询全部书籍

package com.tang.controller;

import com.tang.pojo.Books;
import com.tang.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping; import java.util.List; @Controller
@RequestMapping("/book")
public class BookController { //controller调service层
@Autowired
@Qualifier("BookServiceImpl")
public BookService bookService; //查询全部的书籍,并且返回到一个书籍展示界面
@RequestMapping("/allBook")
public String list(Model model){ List<Books> list = bookService.queryAllBook(); model.addAttribute("list",list); return "allBook";
}
}

7.4.2编写首页 index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<h3>
<a href="${pageContext.request.contextPath}/book/allBook">进入书籍页面</a>
</h3>
</body>
</html>

7.4.3书籍列表页面 allbook.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>书籍展示页面</title>
</head>
<body>
<h1>书籍展示</h1>
</body>
</html>

先测试一下,看会不会报错,我总共遇到三个错误

  • 项目发布失败,检查发现,在项目结构中没有加上lib目录并导入相应库文件,加上后就可以正常发布项目

  • target文件中发现xml和properties都没有,一开始以为是pom文件中的bulid写错了,最后发现项目的pom文件中项目的打包方式写错了,最后将打包方式改为jar的方式即可

  • 然后再继续运行发现又报错说No qualifying bean of type 'com.tang.service.BookService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier("BookServiceImpl")}

解决步骤:

  • 查看这个bean是否注入成功!ok

  • Junit单元测试,看我们的代码是否能够查询出来结果 ok

  • 问题一定不再底层,是spring出了问题

  • SpringMVC,整合的时候没调用到我们的service层的bean:

    • applicationContext.xml没有注入bean
    • web.xml中,我们也绑定过配置文件,发现我们配置的是Spring-mvc.xml这里面没有service bean,解决方方法将web.xml中Spring-mvc.xml改为applicationContext.xml

最终结果

7.4.4美化首页

编写首页 index.jsp


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
<style>
a{
text-decoration: none;/*去除a标签的下划线*/
color: black;
font-size: 18px;
}
h3{
width: 180px;
height: 38px;
margin: 100px auto;
text-align: center;
line-height: 38px;
background: deepskyblue;
border-radius: 5px;
}
</style>
</head>
<body>
<h3>
<a href="${pageContext.request.contextPath}/book/allBook">进入书籍页面</a>
</h3>
</body>
</html>

7.4.5美化书籍展示页面

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>书籍展示页面</title>
<!-- 引入 Bootstrap -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body> <div class="container"> <div class="row clearfix">
<div class="col-md-12 column">
<div class="page-header">
<h1>
<small>书籍列表 —— 显示所有书籍</small>
</h1>
</div>
</div>
</div> <div class="row clearfix">
<div class="col-md-12 column">
<table class="table table-hover table-striped">
<%--表格的标题--%>
<thead>
<tr>
<th>书籍编号</th>
<th>书籍名字</th>
<th>书籍数量</th>
<th>书籍详情</th>
</tr>
</thead>
<%--书籍从数据库中查询出来,从这个list中遍历出来:foreach--%>
<%--表格的身体--%>
<tbody>
<c:forEach var="book" items="${list}">
<tr>
<td>${book.bookID}</td>
<td>${book.bookName}</td>
<td>${book.bookCounts}</td>
<td>${book.detail}</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div> </div> </body>
</html>

运行Tomcat查看运行结果

7.5添加书籍功能

btn-primary(重点蓝)、

btn-success(成功绿)、

btn-info(信息蓝)、

btn-warning(警告橙)、

btn-danger(危险红)

在allBook界面先添加增加书籍的按钮

<div class="row">
<div class="col-md-4 column">
<%--toAddBook--%>
<a class="btn btn-primary" href ="${pageContext.request.contextPath}/book/toAddBook">新增书籍</a>
</div>
</div>

当点击新增书籍按钮后先到controller

BookController代码

@RequestMapping("/toAddBook")
public String toAddPage(){ return "addBook";//经过controller处理之后跳转到增加书籍页面
}

添加书籍前端页面

addBook.jsp


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>新增书籍</title>
<!-- 引入 Bootstrap -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head>
<body>
<div class="container"> <div class="row clearfix">
<div class="col-md-12 column">
<div class="page-header">
<h1>
<small>新增书籍</small>
</h1>
</div>
</div>
</div> <form action="${pageContext.request.contextPath}/book/addBook" method="post">
<div class="form-group">
<label>书籍名称:</label>
<input type="text" name="bookName" class="form-control" required>
</div> <div class="form-group">
<label>书籍数量:</label>
<input type="text" name="bookCounts" class="form-control" required>
</div> <div class="form-group">
<label>书籍描述:</label>
<input type="text" name="detail" class="form-control" required>
</div> <div class="form-group">
<input type="submit" class="form-control" value="添加">
</div>
</form> </div>
</body>
</html>

当在添加书籍页面点击添加之后请求处理界面

BookController代码

//添加书籍的请求
@RequestMapping("/addBook")
public String addBook(Books books){
System.out.println("addBook=>"+books);
bookService.addBook(books);
return "redirect:/book/allBook";//重定向到我们的@RequestMapping("/allBook")请求
}

运行结果

7.6修改书籍

现在展示所有书籍界面的表格中添加操作标题,并且添加修改和删除按钮
allBook.jsp

<td>
<%--当点击修改时先跳转到controller--%>
<a class="btn btn-primary" href="${pageContext.request.contextPath}/book/toUpdate?id=${book.bookID}">修改</a>
&nbsp; |&nbsp;
<a class="btn btn-primary" href="#">删除</a>
</td>

BookController


@RequestMapping("/toUpdate")
public String toUpdatePaper(int id,Model model){
Books books = bookService.queryBookById(id);//到修改页面需要先将该书籍原来的数据查询出来
model.addAttribute("QBooks",books);
return "updateBook";//跳转到修改页面
}

修改页面updateBook.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>修改书籍</title>
<!-- 引入 Bootstrap -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head>
<body>
<div class="container"> <div class="row clearfix">
<div class="col-md-12 column">
<div class="page-header">
<h1>
<small>修改书籍</small>
</h1>
</div>
</div>
</div> <form action="${pageContext.request.contextPath}/book/updateBook" method="post">
<div class="form-group">
<label>书籍名称:</label>
<%--value的值就是拿到该书原来的数据--%>
<input type="text" name="bookName" class="form-control" value="${QBooks.bookName}" required>
</div> <div class="form-group">
<label>书籍数量:</label>
<input type="text" name="bookCounts" class="form-control" value="${QBooks.bookCounts}" required>
</div> <div class="form-group">
<label>书籍描述:</label>
<input type="text" name="detail" class="form-control" value="${QBooks.detail}" required>
</div> <div class="form-group">
<input type="submit" class="form-control" value="修改">
</div>
</form> </div>
</body>
</html>

处理点击修改按钮之后请求

//跳转到修改页面
@RequestMapping("/updateBook")
public String updateBook(Books books){
System.out.println("updateBook=>"+books);
bookService.updateBook(books);
return "redirect:/book/allBook";
}

测试结果



出现的问题:我们提交了修改的SQL请求,但是修改失败,初次考虑,是事务问题,配置完毕事务,依旧失败

看一下SQL语句,能够执行成功:SQL执行失败,修改未完成,解决方法:在前端传递隐藏域

在updateBook.jsp页面的form表单中添加隐藏域

<input type="hidden" name="bookID" value="${QBooks.bookID}">

再次测试

7.7删除书籍

allBook.jsp中点击删除后进行的操作

<a class="btn btn-danger" href="${pageContext.request.contextPath}/book/toDelete/${book.bookID}">删除</a>

点击删除后进入BookController

//删除书籍
@RequestMapping("/toDelete/{bookId}")
public String deleteBook(@PathVariable("bookId") int id){
bookService.deleteBookById(id);
return "redirect:/book/allBook";
}

测试结果

7.8新增搜索功能

BookMapper添加接口

//根据书名查询
Books queryBookName(@Param("bookName") String bookName);

BookMapper.xml

<select id="queryBookName" resultType="Books">
select * from books where bookName=#{bookName}
</select>

service层BookService添加接口

//根据书名查询书籍
Books queryBookName(String bookName);

BookServiceImpl

public Books queryBookName(String bookName) {
return bookMapper.queryBookName(bookName);
}

在所有书籍(allBook.jsp)界面中添加搜索框和搜索按钮

<div class="col-md-4 column">
<%--搜索书籍--%>
<form action="${pageContext.request.contextPath}/book/queryBook" method="post" style="float: right">
<input type="text" name="queryBookName" class="form-control" placeholder="请输入要查询的书籍名称">
<input type="submit" value="查询" class="btn btn-primary">
</form>
</div>

点击搜索先到controller层

//查询书籍
@RequestMapping("/queryBook")
public String queryBook(String queryBookName,Model model){
Books books = bookService.queryBookName(queryBookName); ArrayList<Books> list = new ArrayList<Books>();
list.add(books); model.addAttribute("list",list);
return "allBook";
}

拓展添加一个显示所有书籍的按钮

<a class="btn btn-primary" href ="${pageContext.request.contextPath}/book/allBook">显示全部书籍</a>

启动Tomcat测试



新增功能当未查到时提示未查到

BookController中查询添加如下判断

if(books == null){
list = bookService.queryAllBook();
model.addAttribute("error","未查到");
}

然后在前端界面显示该提示

<span style="color:red; font-weight: bold ">${error}</span>

在启动Tomcat测试



将搜索框搜索按钮以及提示信息横向展示只需要在搜索框的form表单中添加如下属性即可

class="form-inline"

这个是我们的第一个SSM整合案例,一定要烂熟于心!

SSM框架的重要程度是不言而喻的,学到这里,大家已经可以进行基本网站的单独开发。但是这只是增删改查的基本操作。可以说学到这里,大家才算是真正的步入了后台开发的门。也就是能找一个后台相关工作的底线。

或许很多人,工作就做这些事情,但是对于个人的提高来说,还远远不够!

我们后面还要学习一些 SpringMVC 的知识!

8.Ajax

最终的项目结构图

8.1简介

  • AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。

  • AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

  • Ajax 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术。

  • 在 2005 年,Google 通过其 Google Suggest 使 AJAX 变得流行起来。Google Suggest能够自动帮你完成搜索单词。

  • Google Suggest 使用 AJAX 创造出动态性极强的 web 界面:当您在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。

  • 就和国内百度的搜索框一样!

  • 传统的网页(即不用ajax技术的网页),想要更新内容或者提交一个表单,都需要重新加载整个网页。

  • 使用ajax技术的网页,通过在后台服务器进行少量的数据交换,就可以实现异步局部更新。

  • 使用Ajax,用户可以创建接近本地桌面应用的直接、高可用、更丰富、更动态的Web用户界面。

8.2伪造Ajax

8.2.1测试环境

applicationContext.xml以及web.xml中的内容就不在赘述了
AjaxController代码

@RestController
public class AjaxController {
@RequestMapping("/t1")
public String test(){
return "hello";
}
}

测试结果

8.2.2iframe标签来实现

我们可以使用前端的一个标签来伪造一个ajax的样子,就是点击提交按钮后将请求提交给iframe框中,而不是刷新当前页面

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
<!--点击提交按钮就会触发该事件-->
function go(){
//所有的值和变量,提前获取
var url = document.getElementById("url").value;//拿到url的value值
document.getElementById("iframe1").src=url;//将iframe1的src值设置为刚获取的url
}
</script>
</head>
<body>
<div>
<p>请输入地址:</p>
<input type="text" id="url" value="https://www.bilibili.com/">
<input type="button" value="提交" onclick="go()">
</div> <div>
<iframe id="iframe1" style="width: 100%;height: 500px"> </iframe>
</div>
</body>
</html>

测试结果

8.2.3jQuery.ajax

纯JS原生实现Ajax我们不去讲解这里,直接使用jquery提供的,方便学习和使用,避免重复造轮子,有兴趣的同学可以去了解下JS原生XMLHttpRequest !

Ajax的核心是XMLHttpRequest对象(XHR)。XHR为向服务器发送请求和解析服务器响应提供了接口。能够以异步方式从服务器获取新数据。

jQuery 提供多个与 AJAX 有关的方法。

通过 jQuery AJAX 方法,您能够使用 HTTP Get 和 HTTP Post 从远程服务器上请求文本、HTML、XML 或 JSON – 同时您能够把这些外部数据直接载入网页的被选元素中。

jQuery 不是生产者,而是大自然搬运工。

jQuery Ajax本质就是 XMLHttpRequest,对他进行了封装,方便调用!

jQuery.ajax(...)
部分参数:
url:请求地址
type:请求方式,GET、POST(1.9.0之后用method)
headers:请求头
data:要发送的数据
contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
async:是否异步
timeout:设置请求超时时间(毫秒)
beforeSend:发送请求前执行的函数(全局)
complete:完成之后执行的回调函数(全局)
success:成功之后执行的回调函数(全局)
error:失败之后执行的回调函数(全局)
accepts:通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型
dataType:将服务器端返回的数据转换成指定类型
"xml": 将服务器端返回的内容转换成xml格式
"text": 将服务器端返回的内容转换成普通文本格式
"html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
"script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
"json": 将服务器端返回的内容转换成相应的JavaScript对象
"jsonp": JSONP 格式使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数

我们来个简单的测试,使用最原始的HttpServletResponse处理 , .最简单 , 最通用

导入jquery , 可以使用在线的CDN , 也可以下载导入

<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.5.1.min.js"></script>

jQuery官网下载地址

https://jquery.com/download/

在applicationContext中添加静态资源过滤否则,statics中的js文件就不会被打包

<!--静态资源过滤-->
<mvc:default-servlet-handler/>

编写index.jsp

<%--
Created by IntelliJ IDEA.
User: twq
Date: 2022/8/26
Time: 08:19
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.5.1.js"></script> <script>
function a(){
$.post({
url:"${pageContext.request.contextPath}/a1",
data:{"name" : $("#username").val()},
success:function (data){
alert(data);
} })
} </script> </head>
<body> <%--失去焦点的时候,发起一个请求(携带信息)到后台--%>
用户名:<input type="text" id="username" onblur="a()"> </body>
</html>

AjaxController

@RestController
public class AjaxController { @RequestMapping("/a1")
public void a1(String name, HttpServletResponse response) throws IOException { System.out.println();
if("Twq".equals(name)){
response.getWriter().print("true");
}else {
response.getWriter().print("false");
} }
}

测试结果

8.3Springmvc实现

实体类user

package com.tang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor; @Data
@AllArgsConstructor
@NoArgsConstructor
public class User { private String name;
private int age;
private String sex;
}

我们来获取一个集合对象,展示到前端页面

@RequestMapping("/a2")
public List<User> a2(){
List<User> users = new ArrayList<User>(); //添加数据
users.add(new User("唐昊",3,"男"));
users.add(new User("唐三",2,"男"));
users.add(new User("小舞",1,"女"));
return users;
}

前端页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<input type="button" id="btn" value="获取数据"/>
<table width="80%" align="center">
<tr>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
<tbody id="content">
</tbody>
</table> <script src="${pageContext.request.contextPath}/statics/js/jquery-3.5.1.js"></script>
<script> $(function () {
$("#btn").click(function () {//当点击获取数据按钮触发事件
/*
$.post(url,param[可以省略],success(回调函数))
*/
$.post("${pageContext.request.contextPath}/a2",function (data) {
console.log(data)//到这已经获取到了User数据
var html="";
for (var i = 0; i <data.length ; i++) {//获取前端数据,并拼接
html+= "<tr>" +
"<td>" + data[i].name + "</td>" +
"<td>" + data[i].age + "</td>" +
"<td>" + data[i].sex + "</td>" +
"</tr>"
}
$("#content").html(html);//将User数据存入tbody中
});
})
})
</script>
</body>
</html>

8.4注册提示效果

我们再测试一个小Demo,思考一下我们平时注册时候,输入框后面的实时提示怎么做到的;如何优化

我们写一个Controller

@RequestMapping("/a3")
public String ajax3(String name,String pwd){
String msg = "";
//模拟数据库中存在数据
if (name!=null){
if ("admin".equals(name)){
msg = "OK";
}else {
msg = "用户名输入错误";
}
}
if (pwd!=null){
if ("123456".equals(pwd)){
msg = "OK";
}else {
msg = "密码输入有误";
}
}
return msg; //由于@RestController注解,将msg转成json格式返回
}

前端页面 login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>ajax</title>
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.5.1.js"></script>
<script> function a1(){
$.post({
url:"${pageContext.request.contextPath}/a3",
data:{'name':$("#name").val()},
success:function (data) {
if (data.toString()=='OK'){
$("#userInfo").css("color","green");
}else {
$("#userInfo").css("color","red");
}
$("#userInfo").html(data);
}
});
}
function a2(){
$.post({
url:"${pageContext.request.contextPath}/a3",
data:{'pwd':$("#pwd").val()},
success:function (data) {
if (data.toString()=='OK'){
$("#pwdInfo").css("color","green");
}else {
$("#pwdInfo").css("color","red");
}
$("#pwdInfo").html(data);
}
});
} </script>
</head>
<body>
<p>
用户名:<input type="text" id="name" onblur="a1()"/>
<span id="userInfo"></span>
</p>
<p>
密码:<input type="text" id="pwd" onblur="a2()"/>
<span id="pwdInfo"></span>
</p>
</body>
</html>

记得处理json乱码问题

在application.xml中添加如下代码即可解决乱码问题

<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>

测试结果

9.拦截器

9.1概述

SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。

过滤器与拦截器的区别:拦截器是AOP思想的具体应用。

过滤器

  • servlet规范中的一部分,任何java web工程都可以使用

  • 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截

拦截器

  • 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用

  • 拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的

9.2自定义拦截器

那如何实现拦截器呢?

想要自定义拦截器,必须实现 HandlerInterceptor 接口。

  • 新建一个Moudule , springmvc-07-Interceptor , 添加web支持

  • 配置web.xml 和 springmvc-servlet.xml 文件

9.2.1编写一个拦截器

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("===========清理===========");
}
}

9.2.2在springmvc的配置文件中配置拦截器

 <!--关于拦截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路径及其子路径-->
<!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截-->
<!--/admin/** 拦截的是/admin/下的所有-->
<mvc:mapping path="/**"/>
<!--bean配置的就是拦截器-->
<bean class="com.tang.config.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>

9.2.3编写一个Controller接收请求

@RestController
public class TestController { @RequestMapping("/a1")
public String test(){
System.out.println("TestController执行了");
return "hello";
}
}

测试结果

SpringMVC完整版详解的更多相关文章

  1. 常用经典SQL语句大全完整版--详解+实例 (存)

    常用经典SQL语句大全完整版--详解+实例 转 傻豆儿的博客 http://blog.sina.com.cn/shadou2012  http://blog.sina.com.cn/s/blog_84 ...

  2. 常用经典SQL语句大全完整版--详解+实例 《来自网络,很全没整理,寄存与此》

    常用经典SQL语句大全完整版--详解+实例 下列语句部分是Mssql语句,不可以在access中使用. SQL分类: DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE) DML ...

  3. 转 Android Activity之间动画完整版详解

    标签:Android Activity动画详解 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://mzh3344258.blog.5 ...

  4. Mybatis完整版详解

    一.简介 1.什么是MyBatis MyBatis 是一款优秀的持久层框架 它支持自定义 SQL.存储过程以及高级映射. MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作 ...

  5. Spring5完整版详解

    1.Spring 1.1简介 2002,首次退出来Spring框架的雏形:interface21框架 Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,与2004年 ...

  6. SpringMVC 常用注解 详解

    SpringMVC 常用注解 详解 SpringMVC 常用注解 1.@RequestMapping                                      路径映射 2.@Requ ...

  7. springMVC的注解详解

    springmvc常用注解标签详解 1.@Controller 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业 ...

  8. SpringMvc测试框架详解----服务端测试

    随着RESTful Web Service的流行,测试对外的Service是否满足期望也变的必要的.从Spring 3.2开始Spring了Spring Web测试框架,如果版本低于3.2,请使用sp ...

  9. springmvc常用注解详解

    1.@Controller 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ...

随机推荐

  1. 看看CabloyJS是如何实现编辑页面脏标记的

    应用场景 我们在使用Word.Excel时,当修改了内容之后在标题栏会显示脏标记,从而可以明确的告知用户内容有变动.此外,如果在没有保存的情况下关闭窗口,系统会弹出提示框,让用户选择是否放弃修改 那么 ...

  2. 苹果宣布 2022 年 Apple 设计大奖得主

    Apple 今日举办了年度 Apple 设计大奖颁奖仪式,表彰 12 款出类拔萃的 app 与游戏佳作.今年的获奖者包括来自全球各地的开发者.他们通过 app 呈现锐意创新.别出心裁的优美设计体验,以 ...

  3. python中collections.OrderedDict()

    import collections #from collections import OrderededDict my_orderDict=collections.OrderedDict(house ...

  4. SmartIDE v0.1.19 - 码云(Gitee)最有价值开源项目奖项、工作区策略、类虚拟机镜像VMLC、Server安装手册

    SmartIDE v0.1.19 (CLI Build 3909, Server Build 3890) 已经发布,本次Sprint主要完成2个重要特性,工作区策略和类虚拟机容器(VM Like Co ...

  5. 使用node.js如何简单快速的搭建一个websocket聊天应用

    初始化项目 npm init 安装nodejs-websocket npm install nodejs-websocket 创建并编辑启动文件 创建一个名为app.js文件,并且编辑它. var w ...

  6. mysql-安装(windows版本)与登录

    安装mysql 1.MySQL版本 mysql-5.6.35-winx64.zip 2.首先解压到安装目录 3.修改配置文件 复制my-default.ini 重命名为my.ini 然后修改mysql ...

  7. 从一道算法题实现一个文本diff小工具

    众所周知,很多社区都是有内容审核机制的,除了第一次发布,后续的修改也需要审核,最粗暴的方式当然是从头再看一遍,但是编辑肯定想弄死你,显然这样效率比较低,比如就改了一个错别字,再看几遍可能也看不出来,所 ...

  8. 手写一个虚拟DOM库,彻底让你理解diff算法

    所谓虚拟DOM就是用js对象来描述真实DOM,它相对于原生DOM更加轻量,因为真正的DOM对象附带有非常多的属性,另外配合虚拟DOM的diff算法,能以最少的操作来更新DOM,除此之外,也能让Vue和 ...

  9. Java模拟西宝高速公路

    @ 目录 写在前面 一.仿真模拟的具体要求 二.类的设计 2.1 抽象父类PubVehicles 2.2 Expressway类 2.3 Passenger类 2.4 Timer类 2.5 Displ ...

  10. XXXX系统测试计划

    XXXX系统测试计划 目录 XXXX系统测试计划 目标 概述 项目背景 适用范围 组织形式 组织架构图 角色及职责 测试工作分工 团队协作 测试对象 应测试特性 不被测试特性 测试任务安排 系统测试任 ...