SpringMVC

SpringMVC

1. 回顾MVC

MVC:模型 视图 控制器

mvc这种架构模式需要做什么事情?

  1. 将url映射到java类或java类的方法
  2. 与数据库交互 — 封装用户提交的数据-
  3. 处理请求—调用相关的业务处理—封装响应数据-提交控制进行分发
  4. 将响应的数据进行渲染 在 jsp / html 等表示层数据

2. Servlet

  1. 新建一个Maven项目或JavaEE项目

  2. 导入依赖

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.8</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>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>
  1. 导入 jsp servlet依赖
  2. 创建一个普通类继承HttpServlet

3. 初识SpringMVC

官方网站:https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-servlet

3.1 特点

  1. 轻量级,简单易学
  2. 高效 , 基于请求响应的MVC框架
  3. 与Spring兼容性好,无缝结合
  4. 约定优于配置
  5. 功能强大:RESTful、数据验证、格式化、本地化、主题等
  6. 简洁灵活

3.2 中心控制器:DispatcherServlet

请求分发器

其实这个本质也是一个Servlet

img

3.3 执行原理

liuc

执行流程

img

虚线为要开发者实现的

分析:

  1. 用户发送请求,DispatcherServle控制器接收请求并拦截请求。
    • http: //localhost: 8080/springMVC/hello
    • http: //localhost: 8080 表示服务器域名
    • hello表示控制器
    • 以上url表示:请求位于服务器localhost:8080 上的springMVC站点的hello控制器。
  2. DispatcherServlet调用HandlerMapping,查找具体的Handler。
  3. HandlerExecution是具体的Handler,主要作用是根据请求的url找到具体的控制器(controller)
  4. HandlerExecution将解析后的信息返回给DispatcherServlet。
  5. DispatcherServlet调用HandlerAdapter,HandlerAdapter按照特定的规则(实现controller接口)执行Handler。
  6. Handler会让具体的控制器(controller)执行。
  7. 控制器(controller)执行完成后返回给HandlerAdapter一个ModelAndView。
  8. HandlerAdapter把ModerAndView返回给DispatcherServlet。
  9. DispatherServlet把ModelAndView传给ViewResolver。
  10. ViewResolver执行完成后返回给DispatherServlet一个具体的View。
    • viewResolver获取mv的数据;
    • 解析mv的视图名字;
    • 拼接视图名字找到对应的视图;
    • 将数据渲染到视图上。
  11. DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
  12. DispatcherServlet把视图响应呈现给用户。

组件介绍

DispatcherServlet:前端控制器

用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。

HandlerMapping

处理器映射器,HandlerMapping主要用来解析请求的url,找到与之匹配的处理器Handler

Handler

处理器Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。

HandlAdapter

处理器适配器,通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

ViewResolver

视图解析器,View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。

View

视图,springmvc框架提供了很多的View视图类型的支持,包jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

代码没问题是的404解决方法:

  1. 查看控制台输出 ,看一下是不是缺少了jar包。
  2. 如果jar包存在,显示无法输出,就在IDEA的项目发布中添加lib依赖。
  3. 重启Tomcat即可解决!
  4. Tomcat的ApplicationContext 的路径改为 /

4. HelloSpringMVC

4.1 配置文件版

  1. 创建一个Maven,添加web支持

  2. 检查是否有lib依赖

  3. 配置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>
    <!--        2.关联一个springmvc的配置文件-->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc-servlet.xml</param-value>
            </init-param>
    <!--        3.启动级别:1  表示和服务器一起启动-->
            <load-on-startup>1</load-on-startup>
        </servlet>
    
    <!--    4.匹配:"/" 代表匹配所有请求,不包括.jsp    "/*" 代表匹配所有请求,包括.jsp-->
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    
  4. 编写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">
    
        <!--    添加处理器映射器-->
        <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
        <!--    添加处理器适配器-->
        <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
        <!--    添加视图解析器-->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
            <!--        前缀 /WEB-INF/jsp/  代表在WEB-INF里面的jsp包里面-->
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <!--        后缀-->
            <property name="suffix" value=".jsp"/>
        </bean>
    
    
        <!--    注册-->
        <bean id="/hello" class="com.tzeao.controller.HelloController"/>
    
    </beans>
    

    BeanNameUrlHandlerMapping处理器需要通过bean的名字来查找 所以需要注册bean

  5. 记得 springmvc配置文件里面一定要添加 处理器映射器,处理器适配器,视图解析器

  6. jsp页面

    <%--
      Created by IntelliJ IDEA.
      User: 童泽沼
      Date: 2021/7/9 0009
      Time: 1:54
      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>
    
  7. 配置好Tomcat

    路径为"/"

4.2 注解版

  1. 创建Mavan项目

  2. 防止Mavan资源过滤问题

     <!--在build中配置resources,来防止我们资源导出失败的问题-->
        <build>
            <resources>
                <resource>
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.properties</include>
                        <include>**/*.xml</include>
                    </includes>
                    <filtering>false</filtering>
                </resource>
                <resource>
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.properties</include>
                        <include>**/*.xml</include>
                    </includes>
                    <filtering>false</filtering>
                </resource>
            </resources>
        </build>
    
  3. 确定相关依赖全部引入

  4. 配置web.xml

    注意:

    1. web.xml要最新版本
    2. 注册DispatcherServlet
    3. 关联SpringMVC配置文件
    4. 启动级别为1
    5. 映射路径为"/"[不要使用"/*" 会404]
    <?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>
    

    区别:

    1. /:代表拦截除后缀名以外的路径,即它只拦截路径,不拦截带后缀的url,若请求为/user/login.jsp,jsp不会进入DispatcherServlet类,即不会被过滤。
    2. /*:代表拦截所有路径和后缀,会匹配所有的url,若请求为/user/login.jsp,会出现jsp进入DispatcherServlet类,导致找不到对应的controller,所以报404错误。
  5. 配置Springmvc的xml文件

    • 让IOC注解生效
    • 静态资源过滤:HTML,JS,CSS,图片,视频。。
    • 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
           http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    
        <!--    自动扫描包-->
        <context:component-scan base-package="com.tzeao.controller"/>
    
        <!--    让Spring MVC 不处理静态资源-->
        <mvc:default-servlet-handler/>
    
        <!--
        支持MVC注解驱动
           在spring中一般采用@RequestMapping注解来完成映射关系
           要想是@RequestMapping生效
           必须向上下文中注册DefaultAnnotationHandlerMapping
           和一个AnnotationMethodHandlerAdapter实例
           这两个实例分别在类级别和方法级别处理
           而annotation-drive配置会帮助我们自动完成上述两个实例的注入
        -->
        <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>
    
  6. 创建Controller类

    package com.tzeao.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    // 使用注解方式来实现Controller接口
    @Controller
    public class HelloController {
    
    //    对方法进行映射
        @RequestMapping("/hello")
        public String hello(Model model){
    //        封装数据 Model
            model.addAttribute("msg", "Hello,World!");
            return "hello";//jsp名称  被视图解析器处理
        }
    
    }
    
    @RequestMapping()
    在类和方法都有是 url就类似于包的层级关系  .../类/方法
    如果类没有时就直接写方法上的就行
    
  7. 运行

    注意Tomcat尽量只保存一个要打包的项目,然后项目路径为"/"

Snipaste_2021-07-09_23-40-01

5. Controller 及 RestFul风格

5.1 Controller

控制器Controller

  • 控制器复杂提供分为应用程序的行为,通常通过接口定义或注解定义两种
  • 控制器负责解析用户的请求并将其转换为一个模型
  • 在Springmvc中 一个控制器类可以包含多个方法
  • 在Springmvc中 对于Controller的配置方式有很多种

1.实现Controller接口

缺点:一个控制器只能写一个方法

除了web.xml文件改变之外其他基本上不变

  1. 不需要映射器处理器和适配器
  2. 只需要视图解析器
<?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
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">


    <!--    视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <bean class="com.tzeao.controller.HelloController" id="/hello"/>
</beans>

springmvc记得注册bean

2. 使用注解实现

优点:可以写多个方法

需要开启注解扫描和支持

package com.tzeao.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ControllerTest2 {

    @RequestMapping("/hello22")
    public String hello(Model model){
        model.addAttribute("msg", "4354");
        return "hello";
    }
}

@Controller:被这个注解的类,里面的方法如果返回值为String类型的,就会默认走视图解析器

5.2 @RequestMapping

1、@RequestMapping 可以用在类定义处和方法定义处。

  • 类定义处:规定初步的请求映射,相对于web应用的根目录,为父级路径;
  • 方法定义处:进一步细分请求映射,相对于类定义处的URL。如果类定义处没有使用该注解,则直接使用方法标记的URL

注意:@RequestMapping的默认属性为value,所以@RequestMapping(value="/example")和@RequestMapping("/example")是等价的。

2、@RequestMapping除了可以指定URL映射外,还可以指定“请求方法、请求参数和请求头”的映射请求
注解的value、method、params及headers分别指定“请求的URL、请求方法、请求参数及请求头”。它们之间是与的关系,联合使用会使得请求的映射更加精细。

5.3 ReatFul 风格

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,post or get

原始的:http://localhost:8080/add?a=545&b=5665

package com.tzeao.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class RestFulController {
    @RequestMapping("/add")
    public String hello(int a, int b, Model model) {//这里的定义的参数  前端就必须传参 如果没有就会爆505
        int res = a + b;
        model.addAttribute("msg","结果为"+res);
        return "hello";
    }
}

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

请求类型设置:

  1. 通过参数实现

    @RequestMapping(value ="/add/{a}/{b}",method = RequestMethod.DELETE)
    
  2. 通过注解的方式实现

    @GetMapping("")
    @PostMapping()
    @DeleteMapping
    @PatchMapping
    
  • 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

RestFul风格:http://localhost:8080/add/45/45

package com.tzeao.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class RestFulController {
    @RequestMapping("/add/{a}/{b}")//通过@PathVariable注解可以把{}里面的值传递给 方法参数 进行赋值
    public String hello(@PathVariable int a,@PathVariable int b, Model model) {
        int res = a + b;
        model.addAttribute("msg","结果为"+res);
        return "hello";
    }
}

需要使用到一个@PathVariable注解,写在方法变量前面

请求方法不一样:

image-20210710022610533

6. 结果跳转方式

1. ModelAndView

设置ModelAndView对象,根据View的名称和2视图解析器跳到指定的页面

页面:视图解析器前缀+viewname+视图解析器后缀

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>

Controller类创建ModelAndView对象

2. ServletAPI

通过ServletAPI不需要视图解析器

HttpServletRequest  进行输出
HttpServletRequest  进行转发
HttpServletResponse  进行重定向

可以使用javaweb的方法进行页面跳转

@RequestMapping("/add/ss")
public String test(HttpServletRequest rsq, HttpServletResponse resp){
    HttpSession session = rsq.getSession();
    System.out.println(session.getId());
    return "hello";
}
@RequestMapping("/add/ss")
public void test(HttpServletRequest rsq, HttpServletResponse resp) throws ServletException, IOException {
    HttpSession session = rsq.getSession();
    System.out.println(session.getId());
    rsq.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(rsq, resp);
}

3. SpringMVC

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

  1. 转发

    @RequestMapping("/add/ss")
    public String test(){
        
        return "/WEB-INF/jsp/hello.jsp";
    }
    
  2. 转发二:forward

    @RequestMapping("/add/ss")
    public String test(){
    
        return "forward:/WEB-INF/jsp/hello.jsp";
    }
    
  3. 重定向:redirect

    @RequestMapping("/add/ss")
    public String test(){
    
        return "redirect:/WEB-INF/jsp/hello.jsp";
    }
    

-----有视图解析器

  1. 转发

    @RequestMapping("/add/ss")
    public String test(){
    
        return "hello";
    }
    
  2. 重定向:重定向不需要视图解析器,只需要填写正确的路径就行

     @RequestMapping("/add/ss")
        public String test(){
            return "redirect:/a.jsp";
        }
    

7. 数据处理

处理提交数据

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

提交数据:http://localhost:8080/user/a?name=Tzeao

接收:

    @GetMapping("/a")
    public String user(String name, Model model) {
//        1.接收前端参数
        System.out.println("前端接收:"+name);

//        2.将结果返回前端
        model.addAttribute("msg", name);

//        3. 跳转
        return "hello";
    }
}

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

@RequestParam() //通过注解来解决

提交数据:http://localhost:8080/user/a?nameaa=Tzeao

接收:

    @GetMapping("/a")
    public String user(@RequestParam("nameaa") String name, Model model) {
//        1.接收前端参数
        System.out.println("前端接收:"+name);

//        2.将结果返回前端
        model.addAttribute("msg", name);

//        3. 跳转
        return "hello";
    }

3、 提交的是一个对象

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

对象时,会去匹配对象里面的属性名,如果一致就赋值,不一致就匹配不到,为null

提交数据:http://localhost:8080/user/b?name=Tzeao&age=12&id=44

pojo:

package com.tzeao.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

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

controller:

@GetMapping("/b")
public String test(User user){
    System.out.println(user);
    return "hello";
}

返回前端数据

1、ModelAndView

2、Model

3、ModelMap

Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;

ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性;

ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。

8. 乱码问题

过滤器或是使用springMVC自带的过滤器 url-pattern 记得是"/*" 只有这个才会对jsp进行拦截

image-20210710232620377

这个是在参数接收的那一刻就乱码了,使用过滤器可以解决GET请求的乱码,但是POST请求的解决不了

过滤器:

package com.tzeao.filter;

import javax.servlet.*;
import java.io.IOException;

public class EncodingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setCharacterEncoding("utf-8");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

使用配置解决 : 在web.xml

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

缺点:极端情况下对GET不友好

处理方法:

  1. 修改Tomcat配置文件:设置编码

    在Tomcat文件夹里面的servlet.xml

      <Connector port="8080" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443" 
    			   URIEncoding="UTF-8"/>
    
  2. 自定义过滤器【终极大招】

    package com.kuang.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 {
    
       @Override
       public void destroy() {
      }
    
       @Override
       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);
      }
    
       @Override
       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配置一下—注册过滤器

9. JSON 传输数据

介绍:

  1. JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别广泛。
  2. 采用完全独立于编程语言的文本格式来存储和表示数据。
  3. 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
  4. 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

1. 回忆

JSON 键值对

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

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

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"}'
<script type="text/javascript">
     <!--    编写js-->
     let user = {
          "name": "君子慎独",
          "age": 545,
          "sex": "男"
     };
     //将js对象转换为json对象
    let userJson = JSON.stringify(user)

     //将json对象转换为js对象
    let  obj = JSON.parse(userJson);
     console.log(obj);
</script>

2. Controller 返回JSON数据

JSON工具:jackson、fastjson…

jackson使用

1、引入jar包或是依赖

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.4</version>
</dependency>

2、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">
    <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>
    <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>

3、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
       http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--    自动扫描包-->
    <context:component-scan base-package="com.tzeao.controller"/>
    <mvc:default-servlet-handler/>
    <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>

4、实体类

package com.tzeao.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

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

5、controller

@ResponseBody//添加了这个注解后,就不会走视图解析器,而是直接返回一个字符串
//@RestController // 所有方法都不走视图解析器
package com.tzeao.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.tzeao.pojo.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

//@Controller //会走视图解析器
@RestController // 所有方法都不走视图解析器
public class JSONController {
    @RequestMapping("/j1")
    private String json1() throws JsonProcessingException {
//        jackson   ObjectMapper对象
        ObjectMapper mapper = new ObjectMapper();
        User user = new User(45, "君子慎独", 54);
//       把一个值或对象 转为字符串
        String string = mapper.writeValueAsString(user);
        return string;
    }

    @RequestMapping("/j2")
    public String json2() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();

        ArrayList<User> users = new ArrayList<>();
        User user1 = new User(45, "君子慎独1", 45);
        User user2 = new User(46, "君子慎独2", 512);
        User user3 = new User(47, "君子慎独3", 1254);
        User user4 = new User(48, "君子慎独4", 12);
        User user5 = new User(49, "君子慎独5", 1254);

        users.add(user1);
        users.add(user2);
        users.add(user3);
        users.add(user4);
        users.add(user5);

        String string = mapper.writeValueAsString(users);
        return string;
    }

    @RequestMapping("/j3")
    public String json3() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
//     1. 使用mapper自带的方法   不使用时间戳
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        Date date = new Date();

//       2. 通过代码转换格式  不让解析后变为时间戳
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = dateFormat.format(date);
        mapper.setDateFormat(dateFormat);
//        Sun Jul 11 18:36:56 CST 2021  解析为  1625999816508  时间戳
//      ObjectMapper 时间解析后默认格式是:时间戳
        return mapper.writeValueAsString(date);
    }

}

写工具类时,如果有多个一样的可以使用重载,然后有些直接返回已经有的方法,减少代码重复性

public class JsonUtils {
    //重载下面的方法
    public static String getJson(Object object){
        // 直接调用下面重复的代码方法,然后不需要使用的给默认值
        return getJson(object,"yyyy-MM-dd HH:mm:ss");
    }
    
    public static String getJson(Object object,String dateFormat){
        ObjectMapper mapper = new ObjectMapper();
        //不使用时间戳的方式
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
        //自定义日期的格式
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        mapper.setDateFormat(sdf);
        try {
            return mapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

乱码问题:json必须解决的问题

注解方式:

@RequestMapping(value = "/j1",produces = "application/json;charset=utf-8")

xml配置:使用jackson就可以配置这个

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

FastJson的使用

fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现:

  • json对象与JavaBean对象的转换;
  • 实现JavaBean对象与json字符串的转换;
  • 实现json对象与json字符串的转换。

实现json的转换方法很多,最后的实现结果都是一样的。

1、导包

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.76</version>
</dependency>

fastjson 三个主要的类:

  • JSONObject 代表 json 对象
  • JSONArray 代表 json 对象数组
  • JSON代表 JSONObject和JSONArray的转化
@RequestMapping("/j4")
public String json4() {

    ArrayList<User> user = new ArrayList<>();
    User user1 = new User(45, "君子慎独1", 45);
    User user2 = new User(46, "君子慎独2", 512);
    User user3 = new User(47, "君子慎独3", 1254);
    User user4 = new User(48, "君子慎独4", 12);
    User user5 = new User(49, "君子慎独5", 1254);

    user.add(user1);
    user.add(user2);
    user.add(user3);
    user.add(user4);
    user.add(user5);

    System.out.println("*******Java对象 转 JSON字符串*******");
    String str1 = JSON.toJSONString(user);
    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);

    return str1;
}

10. 整合SSM

1- 创建一个数据库

CREATE DATABASE `ssmbuild`;

USE `ssmbuild`;

CREATE TABLE `books`(
    `bookID` INT(10) NOT NULL AUTO_INCREMENT COMMENT '书id',
    `bookName` VARCHAR(100) NOT NULL COMMENT '书名',
    `bookCounts` INT(11) NOT NULL COMMENT '数量',
    `detail` VARCHAR(200) NOT NULL COMMENT '描述',
    KEY `bookID`(`bookID`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `books`(`bookID`,`bookName`,`bookCounts`,`detail`) VALUES
(1,'Java',1,'从入门到放弃'),
(2,'MySQL',10,'从删库到跑路'),
(3,'Linux',5,'从进门到进牢');

2- 创建一个Maven项目,添加web支持

3- 导入依赖

<!--        junit-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
</dependency>
<!--        数据库驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>
</dependency>
<!--        数据库连接池-->
<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.5</version>
</dependency>
<!--servlet  jsp  jstl-->
<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.7</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.6</version>
</dependency>
<!--        spring-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.8</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.8</version>
</dependency>

4- 静态资源问题

5- 连接数据库

6- 配置文件

mybatis

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

</configuration>

applicationContext.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:tx="http://www.springframework.org/schema/tx"
       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
                           http://www.springframework.org/schema/mvc/spring-mvc.xsd 
                           http://www.springframework.org/schema/tx 
                           http://www.springframework.org/schema/tx/spring-tx.xsd">
</beans>

7- 创建MVC结构包

10.1 Mybatis

  1. database.properties

    driver=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/ssmbuild?allowPublicKeyRetrieval=true&useSSL=true&userUnicode=true&characterEncoding=UTF-8
    user=root
    password=123456
    
  2. 创建数据库接口

  3. 配置核心配置文件

    <?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>
        <settings>
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
        <!--    起别名-->
        <typeAliases>
            <package name="com.tzeao.pojo"/>
        </typeAliases>
    
        <mappers>
            <mapper class="com.tzeao.dao.BookMapper"/>
        </mappers>
    </configuration>
    
  4. 配置mapper文件

    <?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.tzeao.dao.BookMapper">
        <insert id="addBook" parameterType="Books">
            insert into ssmbuild.books(bookName, bookCounts, detail)
            values (#{bookName}, #{bookCounts}, #{detail});
        </insert>
    
        <delete id="deleteBookById" parameterType="_int">
            delete
            from ssmbuild.books
            where bookID = #{bookID};
        </delete>
    
        <update id="updateBook" parameterType="Books">
            update ssmbuild.books
            set BookName   = #{BookName},
            bookCounts = #{bookCounts},
            detail     = #{detail}
            where bookID = #{bookID};
        </update>
    
        <select id="queryBookById" resultType="Books">
            select *
            from ssmbuild.books
            where bookID = #{bookID};
        </select>
    
        <select id="queryAllBook" resultType="Books">
            select *
            from ssmbuild.books;
        </select>
    </mapper>
    
  5. 绑定mapper文件

10.2 Spring

  1. 创建一个整合Spring-Mybatis的文件 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
    http://www.springframework.org/schema/context/spring-context.xsd">
    <!--    1. 关联数据库配置文件-->
        <context:property-placeholder location="classpath:database.properties"/>
    
            <!--    数据库连接池-->
            <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
                <property name="driverClass" value="${driver}"/>
                <property name="jdbcUrl" value="${url}"/>
                <property name="user" value="${username}"/>
                <property name="password" value="${password}"/>
    
                <!--  c3p0私有属性-->
                <property name="maxPoolSize" value="30"/>
                <property name="minPoolSize" value="10"/>
                <!--  关闭连接后不自动commit-->
                <property name="autoCommitOnClose" value="false"/>
                <!--  获取连接超时时间-->
                <property name="checkoutTimeout" value="10000"/>
                <!--  获取连接失败重新连接次数-->
                <property name="acquireRetryAttempts" value="2"/>
                </bean>
    
                <!--    sqlSessionFactory-->
                <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
                    <property name="dataSource" ref="dataSource"/>
                    <!--    绑定mybatis的核心配置文件-->
                    <property name="configLocation" value="classpath:mybatis-config.xml"/>
                    </bean>
    
                    <!--    配置dao扫描包,动态实现Dao接口注入到spring容器中-->
                    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
                        <!--        注入sqlSessionFactory-->
                        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
                        <!--        要扫描的dao包-->
                        <property name="basePackage" value="com.tzeao.dao"/>
                        </bean>
                        </beans>
    
  2. 创建业务层 spring-service.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
                               http://www.springframework.org/schema/context/spring-context.xsd">
        <!--    扫描service下的包-->
        <context:component-scan base-package="com.tzeao.service"/>
    
        <!--    将所有 业务类注入到Spring,可以通过配置或注解实现-->
        <bean id="BookServiceImpl" class="com.tzeao.service.BookServiceImpl">
            <property name="bookMapper" ref="bookMapper"/>
        </bean>
    
        <!--    声明式事务-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <!--    aop事务支持 没有设置的话就默认-->
        <!--    aop事务支持   没有设置的话就默认-->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="*" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
        <aop:config>
            <aop:pointcut id="txPointCut" expression="execution(* com.tzeao.dao.*.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
        </aop:config>
    </beans>
    
  3. 可以使用注解开发的。。。这里用到的都是配置文件开发

10.3 SpringMVC

  1. 开启javaweb框架支持

  2. 配置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">
    
        <!--    Dispatcher-->
        <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>
        <!--    session过期时间  15分钟-->
        <session-config>
            <session-timeout>15</session-timeout>
        </session-config>
    </web-app>
    
  3. 配置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: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/context
                               http://www.springframework.org/schema/context/spring-context.xsd
                               http://www.springframework.org/schema/mvc
                               http://www.springframework.org/schema/mvc/spring-mvc.xsd">
        <!--1. 注解驱动-->
        <mvc:annotation-driven/>
        <!--2.静态资源过滤-->
        <mvc:default-servlet-handler/>
        <!--3.扫描包-->
        <context:component-scan base-package="com.tzeao.controller"/>
        <!--4.视图解析器-->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <property name="suffix" value=".jsp"/>
        </bean>
    </beans>
    

整合结束!!!!!

其他编写:

  1. Controller

    package com.tzeao.controller;
    
    import com.tzeao.pojo.Books;
    import com.tzeao.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.ArrayList;
    import java.util.List;
    
    @Controller
    @RequestMapping("/book")
    public class BookController {
        //    controller层 调 service层
        @Autowired
        @Qualifier("BookServiceImpl")
        private BookService bookService;
    
        @RequestMapping("/allBook")
        public String list(Model model) {
            List<Books> list = bookService.queryAllBook();
            model.addAttribute("list", list);
            return "allBook";
        }
    
        //    跳转
        @RequestMapping("/toAddBook")
        public String toAddPage() {
            return "addBook";
        }
    
        //    添加
        @RequestMapping("/addBook")
        public String addBook(Books books) {
            System.out.println(books);
            bookService.addBook(books);
            return "redirect:/book/allBook";
        }
    
        //    跳转到修改页面
        @RequestMapping("/toUpdatePage")
        public String toUpdatePage(int id,String name, Model model) {
    
            if (name.equals("无")){
                System.err.println(name);
                return "addBook";
            }else {
                Books books = bookService.queryBookById(id);
                model.addAttribute("book", books);
            }
            return "updateBook";
        }
    
        //    修改
        @RequestMapping("/updateBook")
        public String updateBook(Books books) {
            System.out.println(books);
            bookService.updateBook(books);
            return "redirect:/book/allBook";
        }
    
        //    删除
        @RequestMapping("/deleteBook")
        public String deleteBook(int id,String name) {
            if (name.equals("无")){
                return "redirect:/book/allBook";
            }else {
                bookService.deleteBookById(id);
            }
            return "redirect:/book/allBook";
        }
    
        //    查询书籍
        @RequestMapping("/queryBook")
        public String queryBook(String queryBookName, Model model) {
            List<Books> list = bookService.queryBookByName(queryBookName);
            if (list.size()!= 0){
                model.addAttribute("list", list);
            }else if (!queryBookName.equals("")){
                Books noList = new Books(0,"无",0,"无");
                ArrayList<Books> books = new ArrayList<>();
                books.add(noList);
                model.addAttribute("list", books);
                model.addAttribute("error", "没有该书籍");
            }else {
                return "redirect:/book/allBook";
            }
            return "allBook";
        }
    }
    
  2. dao

    package com.tzeao.dao;
    
    import com.tzeao.pojo.Books;
    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    
    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();
    
        //    搜索框查询
        List<Books> queryBookByName(@Param("bookName") String name);
    
    }
    
    <?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.tzeao.dao.BookMapper">
        <insert id="addBook" parameterType="Books">
            insert into ssmbuild.books(bookName, bookCounts, detail)
            values (#{bookName}, #{bookCounts}, #{detail});
        </insert>
    
        <delete id="deleteBookById" parameterType="_int">
            delete
            from ssmbuild.books
            where bookID = #{bookID};
        </delete>
    
        <update id="updateBook" parameterType="Books">
            update ssmbuild.books
            set BookName   = #{bookName},
                bookCounts = #{bookCounts},
                detail     = #{detail}
            where bookID = #{bookID};
        </update>
    
        <select id="queryBookById" resultType="Books">
            select *
            from ssmbuild.books
            where bookID = #{bookID};
        </select>
    
        <select id="queryAllBook" resultType="Books">
            select *
            from ssmbuild.books;
        </select>
    
        <select id="queryBookByName" resultType="Books">
            select *
            from ssmbuild.books
            where bookName = #{bookName};
        </select>
    </mapper>
    
  3. pojo

    package com.tzeao.pojo;
    
    public class Books {
    
        private int bookID;
        private String bookName;
        private int bookCounts;
        private String detail;
    
        public Books() {
        }
    
        public Books(int bookID, String bookName, int bookCounts, String detail) {
            this.bookID = bookID;
            this.bookName = bookName;
            this.bookCounts = bookCounts;
            this.detail = detail;
        }
    
        public int getBookID() {
            return bookID;
        }
    
        public void setBookID(int bookID) {
            this.bookID = bookID;
        }
    
        public String getBookName() {
            return bookName;
        }
    
        public void setBookName(String bookName) {
            this.bookName = bookName;
        }
    
        public int getBookCounts() {
            return bookCounts;
        }
    
        public void setBookCounts(int bookCounts) {
            this.bookCounts = bookCounts;
        }
    
        public String getDetail() {
            return detail;
        }
    
        public void setDetail(String detail) {
            this.detail = detail;
        }
    
        @Override
        public String toString() {
            return "Books{" +
                "bookID=" + bookID +
                ", bookName='" + bookName + '\'' +
                ", bookCounts=" + bookCounts +
                ", detail='" + detail + '\'' +
                '}';
        }
    }
    
  4. serice

    package com.tzeao.service;
    
    import com.tzeao.dao.BookMapper;
    import com.tzeao.pojo.Books;
    
    import java.util.List;
    
    
    public class BookServiceImpl implements BookService {
        //业务层  调用 dao层 : 组合Dao层
    
        private BookMapper bookMapper;
    
        public void setBookMapper(BookMapper bookMapper) {
            this.bookMapper = bookMapper;
        }
    
        @Override
        public int addBook(Books books) {
            return bookMapper.addBook(books);
        }
    
        @Override
        public int deleteBookById(int id) {
            return bookMapper.deleteBookById(id);
        }
    
        @Override
        public int updateBook(Books books) {
            return bookMapper.updateBook(books);
        }
    
        @Override
        public Books queryBookById(int id) {
            return bookMapper.queryBookById(id);
        }
    
        @Override
        public List<Books> queryAllBook() {
            return bookMapper.queryAllBook();
        }
    
        @Override
        public List<Books> queryBookByName(String name) {
            return bookMapper.queryBookByName(name);
        }
    }
    
    package com.tzeao.service;
    
    import com.tzeao.pojo.Books;
    
    import java.util.List;
    
    public interface BookService {
        //    增
        int addBook(Books books);
    
        //    删
        int deleteBookById(int id);
    
        //    改
        int updateBook(Books books);
    
        //    查
        Books queryBookById(int id);
    
        List<Books> queryAllBook();
    
        List<Books> queryBookByName(String name);
    }
    

注意:除查询之外的操作都需要提交事务

image-20210712034950324

记得检查Artifacts里面是否有lib包,没有会启动不了Tomcat ,每次引入新的依赖需要重新导入lib里面

错误:

java.sql.SQLException: Access denied for user ‘童泽沼’@‘localhost’ (using password: YES)

解决:把properties文件的username 改为其他的 例如user

然后连接那里也改为对应的

java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed

数据库url,添加allowPublicKeyRetrieval=true

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):

一般是dao/mapper包的两个名称不一致

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘com.tzeao.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(value=BookServiceImpl)}

image-20210712232520000

问题:bean不存在

排查:
1. 查看bean是否注入成功
2. junit单元测试,看代码是否有查询结果
3. 如果前两个都没问题,那就不是底层代码问题,是Spring有问题  把注入改为直接new出来  报空指针异常
4. springmvc整合时没有调用service层的bean
 1. applicationContext.xml 没有注入bean
 2. web.xml 也绑定过配置文件--- 在web.xml 的上下文配置中 加入总spring配置文件

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0’: Cannot resolve reference to bean ‘txPointCut’ while setting bean property ‘pointcut’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘txPointCut’: Lookup method resolution failed; nested exception is java.lang.IllegalStateException: Failed to introspect Class [org.springframework.aop.aspectj.AspectJExpressionPointcut] from ClassLoader [ParallelWebappClassLoader
context: ROOT
delegate: false
----------> Parent Classloader:
java.net.URLClassLoader@7d6f77cc

lib包里面没有织入依赖包 aspectjweaver

org.apache.ibatis.reflection.ReflectionException: There is no getter for property named ‘BookName’ in ‘class com.tzeao.pojo.Books’

500错误的,代码确定字段名名称的情况下,那就是sql语句有问题

需要写jsp有路径提示

那么这个就要这样的

image-20210713223118719

如果没有就,先把spring删除,再点加号重新添加

image-20210713223142165

war

pom.xml里面加这个有可能会自动导包

lib

image-20210714001916526

11. ajax

正常使用就行,注意跨域问题

12. 拦截器

概述:

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

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

过滤器

  • servlet规范中的一部分,任何java web工程都可以使用
  • 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截

拦截器

  • 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
  • 拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的

自定义拦截器

  1. 创建项目,配置好环境

  2. 创建一个工具包,实现HandlerInterceptor接口

    package com.tzeao.config;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class MyInterceptor implements HandlerInterceptor {
    
        //  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("===========清理==============");
        }
    }
    
    
  3. springmvc文件配置

    <!--    拦截器配置-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--            "/**" 代表拦截包括这个请求下面的所有请求   -->
            <mvc:mapping path="/**"/>
            <bean class="com.tzeao.config.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
    

登录拦截:

package com.tzeao.config;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class LoginController implements HandlerInterceptor {

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();

//        判断是否需要放行
if (request.getRequestURI().contains("goLogin")) {
return true;
} 
// contains("login") 代表login路径
if (request.getRequestURI().contains("login")) {
return true;
}
if (session.getAttribute("username") != null) {
return true;
}
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
package com.tzeao.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;
@RequestMapping("/user")
@Controller
public class LoginController {
    @RequestMapping("/login")
    public String longin(String username, String paw, HttpSession session){
        session.setAttribute("userLoginInfo",username);
        return "main";
    }
    @RequestMapping("/main")
    public String main(){
        return "main";
    }
    @RequestMapping("/giLogin")
    public String goLogin(){
        return "login";
    }

}

13. 文件上传-下载

需要依赖

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.9.0</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.0.1</version>
</dependency>

springmvc.xml配置

bena的id必须为:multipartResolver , 否则上传文件会报400的错误

<!--ID必须为multipartResolver,否则就400问题-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
    <property name="defaultEncoding" value="utf-8"/>
    <!--设置文件上传的大小限制-->
    <property name="maxUploadSize" value="1048576"/>
    <property name="maxInMemorySize" value="40960"/>
</bean>

采用流的方式上传文件

Tip:@RequestParam(“file”) 将name=file控件得到的文件封装成CommonsMultipartFile 对象,我们在上面的前端配置的地方将input类型为file的标签的name设置为了file,所以这里注解内也为file

实现思路:

  1. 首先获取上传文件的文件名
  2. 设置上传文件的保存路径
  3. 使用字节输入流和字节输出流实现文件上传
  4. 关闭流
package com.tzeao.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

@Controller
public class FileController {
    //采用流的方式上传文件
    @RequestMapping("/upload")
    @ResponseBody
    public String upload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
        //获得文件名
        String filename = file.getOriginalFilename();
        if ("".equals(filename)){
            return "文件不存在";
        }
        //上传文件保存路径
        String path = request.getServletContext().getRealPath("/upload");
        File realPath = new File(path);
        if (!realPath.exists()){
            realPath.mkdir();
        }
        //文件上传
        InputStream inputStream = file.getInputStream();
        FileOutputStream outputStream = new FileOutputStream(new File(realPath, filename));
        int len = 0;
        byte[] bytes = new byte[1024];
        while ((len=inputStream.read(bytes))!=-1){
            outputStream.write(bytes,0,len);
            outputStream.flush();
        }
        //关闭流
        outputStream.close();
        inputStream.close();
        return "上传完毕";
    }
}

使用file.Transto上传文件

除了使用流的方式上传文件,我们还可以使用Transto方法上传文件

@Controller
public class FileController {
    //采用file.Transto上传文件
    @RequestMapping("/upload2")
    @ResponseBody
    public String upload2(@RequestParam("file") CommonsMultipartFile file,HttpServletRequest request) throws IOException {
        //上传文件保存路径
        String path = request.getServletContext().getRealPath("/upload");
        File realPath = new File(path);
        if (!realPath.exists()){
            realPath.mkdir();
        }
        //transferTo将文件写入磁盘,参数传入一个文件
        file.transferTo(new File(realPath+"/"+file.getOriginalFilename()));
        return "上传完毕";
    }
}

文件过大时会报错的

SpringMVC实现文件下载

package org.westos.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
@Controller
public class DownloadController {
    @RequestMapping("/download2")
    public String download(HttpServletRequest request, HttpServletResponse response) {
        String fileName = "1.png";
        System.out.println(fileName);
        response.setContentType("text/html;charset=utf-8");
        try {
            request.setCharacterEncoding("UTF-8");//设定请求字符编码
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
        BufferedInputStream bis = null;//创建输入输出流
        BufferedOutputStream bos = null;
        String realPath = request.getSession().getServletContext().getRealPath("/") + "upload/";//获取文件真实路径
        System.out.println(realPath);
        String downLoadPath = realPath + fileName;
        System.out.println(downLoadPath);
        try {
            long fileLength = new File(downLoadPath).length();//获取文件长度
            //设置响应头信息;【固定的不用记,保存即可】
            response.setContentType("application/x-msdownload;");
            response.setHeader("Content-disposition", "attachment; filename=" + new String(fileName.getBytes("utf-8"), "ISO8859-1"));
            response.setHeader("Content-Length", String.valueOf(fileLength));
            bis = new BufferedInputStream(new FileInputStream(downLoadPath));//创建输入输出流实例
            bos = new BufferedOutputStream(response.getOutputStream());
            byte[] buff = new byte[2048];//创建字节缓冲大小
            int bytesRead;
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bis != null)
                try {
                    bis.close();//关闭输入流
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            if (bos != null)
                try {
                    bos.close();//关闭输出流
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }
        return null;
    }
}

使用springmvc

  @RequestMapping("/download")
    public String download(HttpServletResponse response, HttpServletRequest request) {
//        要下载的图片地址
        String path = request.getServletContext().getRealPath("/upload");
        String fileName = "jj.jpg";

//        设置response响应头
        response.reset();//设置页面不缓存,清空buffer
        response.setCharacterEncoding("UTF-8");//编码
        response.setContentType("multipart/form-data");//二进制传输数据

//        设置响应头
        try {
            response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));
            File file = new File(path, fileName);

            FileInputStream fileInputStream = new FileInputStream(file);

            ServletOutputStream outputStream = response.getOutputStream();

            byte[] bytes = new byte[1024];
            int index = 0;

            while ((index = fileInputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, index);
                outputStream.flush();
            }
            outputStream.close();
            fileInputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

注意:URLEncoder 的包是这个import java.net.URLEncoder,导错会报404

图片保存在web里面

mybatis---- 数据库

spring — ioc aop

springmvc — 拦截器,过滤器,请求分发器

posted @ 2022-03-30 19:04  Tzeao  阅读(46)  评论(0)    收藏  举报