狂神说springmvc

1. 基础了解

1.1 mvc

MVC三层架构

spring:ioc 和 aop

springmvc:springmvc的执行流程

springmvc:ssm框架整合

mvc

mvc是一种软件设计规范, 将业务的逻辑,数据,显示分离的方式来组织代码

  • 模型(dao,service)
  • 视图(jsp)
  • 控制器(servlet)

mvc框架做哪些事情?

  • 将url映射到java类或java类的方法
  • 封装用户提交的数据
  • 处理请求-调用相关的业务处理-封装响应数据
  • 将相应的数据进行渲染,jsp/html 等表示层数据

1.2 springmvc

我们为什么要学习springmvc

  • 轻量级,简单易学
  • 高效,基于请求响应的mvc框架
  • 与spring兼容性好,无缝结合
  • 约定大于配置
  • 功能强大:RESTful,数据验证,格式化,本地化,主题等
  • 简洁灵活
  • 使用的人多,使用的公司多

dispatcherservlet继承关系

在这里插入图片描述

springmvc执行流程

在这里插入图片描述

2.入门sprigmvc

2.1 hello 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">

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

    <!--/:匹配所有请求,不包括jsp-->
    <!--/*:匹配所有请求,包括jsp-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>
  • 配置文件
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启注解支持-->
    <context:annotation-config></context:annotation-config>

    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

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

    <!--handler-->
    <bean id="/hello" class="edu.controller.HelloController"></bean>

</beans>

特别说明:如果aop没有定义切入点等,就不要使用aop相关约束

  • servlet
package edu.controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

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

public class HelloController implements Controller {
    
    

    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
    
    
        ModelAndView modelAndView = new ModelAndView();

        modelAndView.addObject("msg", "hello springmvc!");

        modelAndView.setViewName("hello");

        return modelAndView;
    }
}

  • jsp 文件放在web-inf文件夹下,客户端不能直接访问,保护视图安全
<%--
  Created by IntelliJ IDEA.
  User: root
  Date: 2021/10/1
  Time: 11:16
  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>
  <h1>${
    
    msg}</h1>
</body>
</html>

有时候我们会发现代码没问题但是访问404,这个时候我们就要查看project struct然后查看artifacts结构下,看看项目的web-inf目录下是否有相应的jar包,因为tomcat运行需要相应的jar包依赖,如果没有,就在web-inf下新建一个lib包,然后把所有的maven依赖加入其中,然后重启tomcat即可

  • 效果

在这里插入图片描述


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hd1gInjs-1633245411551)(狂神说springmvc.assets/image-20211001141137950.png)]

其中实线部分是springmvc做的,虚线是程序员做的

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

    <!--配置DispatcherServlet: 这个是springmvc的核心:请求分发器,前端控制器-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--DispatcherServlet要绑定springmvc的配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
        <!--启动级别:1-->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--/:匹配所有请求,不包括jsp-->
    <!--/*:匹配所有请求,包括jsp-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>
  • 配置springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://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">

    <!--开启注解支持-->
    <context:annotation-config></context:annotation-config>

    <!--扫描包-->
    <context:component-scan base-package="edu.controller"></context:component-scan>

    <!--让springmvc不处理静态资源-->
    <mvc:default-servlet-handler></mvc:default-servlet-handler>

    <!--自动配置映射器和适配器-->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!--配置视图解析器  *模板引擎 Thymeleaf freemarker*
        1.获取ModelAndView的数据
        2.解析ModelAndView的视图名字
        3.拼接视图名字,找到对应的视图
        4.将数据渲染到这个视图上
    -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <!--后缀-->
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!--BeanNameUrlHandlerMapping:bean  handler-->


</beans>
  • 书写controller
package edu.controller;

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

/*
* 如果类上也加入了RequestMapping注解,那么访问路径就要加上这一部分内容,相当于加了一个分级
* */

@Controller
@RequestMapping("HelloController")
public class HelloController {
    
    


    @RequestMapping("/hello")
    public String hello(Model model){
    
    
        // 封装数据
        model.addAttribute("msg", "hello,springmvc!");

        return "hello";  // 会被视图解析器处理,这里就写视图的名称
    }
}

  • 结果

在这里插入图片描述

3.springmvc再了解

3.1 controller and restful风格

控制器controller

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

controller实现

  • 实现接口Controller,同时将实现类注入spring容器中
    • 实现Controller接口定义控制器是比较老的办法,不推荐使用
    • 一个控制器中只能有一个方法,多个方法需要定义多个controller,不方便
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.web.servlet.mvc;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.ModelAndView;

@FunctionalInterface
public interface Controller {
    
    
    @Nullable
    ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}

  • 使用@Controller注解
    • 注解的类中的所有方法,如果返回值是string并且有具体的页面可以跳转,就会被视图解析器解析
    • 可以定义多个方法
    • 方法中可以定义多种模型和视图类
    • 多个方法可以对应一个视图,但是其中的数据是不一样的

restful风格

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

  • 以前的方式:http://localhost:8080/add?a=1&b=2
  • 现在的方式:http://localhost:8080/add/1/2

传参的时候,只需要在处理方法上对应的变量位置加上@PathVariable注释,就可以使用restful风格的url了

  • 样例
package edu.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 {
    
    

    /*
    * 原来的风格:http://localhost:8080/add?a=1&b=2
    * restful风格:http://localhost:8080/add/a/b
     * */
    @RequestMapping("/add/{a}/{b}")
    public String test01(@PathVariable int a, @PathVariable int b, Model model){
    
    
        int res = a + b;
        model.addAttribute("msg", "res:" + res);

        return "hello";
    }
}

restful同时也具有更多的请求方式

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.web.bind.annotation;

public enum RequestMethod {
    
    
    GET,
    HEAD,
    POST,
    PUT,
    PATCH,
    DELETE,
    OPTIONS,
    TRACE;

    private RequestMethod() {
    
    
    }
}

同时可以在请求的时候指定请求的方式(例如使用get方式请求)

package edu.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;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class RestfulController {
    
    
    
    @RequestMapping(value = "/add/{a}/{b}", method = RequestMethod.GET)
    public String test01(@PathVariable int a, @PathVariable int b, Model model){
    
    
        int res = a + b;
        model.addAttribute("msg", "res:" + res);

        return "hello";
    }
}

所有的地址栏请求默认都是GET方式

方法级别的注解变体有如下几个

@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
  • 可以同时用不同的请求方式请求相同的路径,我们可以在这上面做不同的处理

例子

package edu.controller;

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

@Controller
public class RestfulController {
    
    

    @RequestMapping(value = "/add/{a}/{b}", method = RequestMethod.GET)
    public String test01(@PathVariable int a, @PathVariable int b, Model model){
    
    
        int res = a + b;
        model.addAttribute("msg", "res:" + res);

        return "hello";
    }
    
    @PostMapping("/add/{a}/{b}")
    public String test02(@PathVariable int a, @PathVariable int b, Model model){
    
    
        int res = a + b;
        model.addAttribute("msg", "second res:" + res);

        return "hello";
    }
}

使用路径变量的好处

  • 使路径变的更加简洁
  • 获得参数更加方便,框架会自动进行类型转换
  • 通过路径变量的类型可以约束访问的参数,如果类型不一样,则访问的不到对应的请求方法.
  • 更加安全

3.2 @RequestMapping注解

@RequestMapping("/xxx")

  • @RequestMapping注解用于映射url到控制器类或一个特定处理程序的方法.可用于类或方法上.用于类上,表示类中所有相应请求的方法都是以该地址作为父路径

  • 只注解在方法上 http:locahost:8080/项目名/方法上的注解内容

  • 注解在类和方法上 http:locahost:8080/项目名/类上的注解内容/方法上的注解内容

3.3 springmvc结果跳转方式

3.3.1 ModelAndView

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

页面:{视图解析器前缀}+viewName+{视图解析器后缀}

视图解析器

<!--配置视图解析器  *模板引擎 Thymeleaf freemarker*
        1.获取ModelAndView的数据
        2.解析ModelAndView的视图名字
        3.拼接视图名字,找到对应的视图
        4.将数据渲染到这个视图上
    -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
    <!--前缀-->
    <property name="prefix" value="/WEB-INF/jsp/"></property>
    <!--后缀-->
    <property name="suffix" value=".jsp"></property>
</bean>

package edu.controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

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

public class HelloController implements Controller {
    
    

    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
    
    
        // ModelAndView  模型和视图
        ModelAndView modelAndView = new ModelAndView();

        // 封装对象
        modelAndView.addObject("msg", "hello springmvc!");

        // 封装要跳转的视图,放在ModelAndView中
        modelAndView.setViewName("hello");

        return modelAndView;
    }
}

3.3.2 ServletAPI

通过设置ServletAPI来进行页面跳转,不需要视图解析器:

  • 通过HttpServletResponse进行输出
  • 通过HttpServletResponse实现重定向
  • 通过HttpServletRequest实现请求转发

为什么可以直接用?

因为controller本身就是一个servlet

3.3.3 通过springmvc

通过springmvc来实现,无需视图解析器

package edu.controller;

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

@Controller
public class springmvcController {
    
    

    @GetMapping("/t1")
    public String test01(Model model){
    
    
        model.addAttribute("msg", "转发1");
        return "/WEB-INF/jsp/hello.jsp";
    }

    @GetMapping("/t2")
    public String test02(Model model){
    
    
        model.addAttribute("msg", "转发2");
        return "forward:/WEB-INF/jsp/hello.jsp";
    }

    @RequestMapping("/t3")
    public String test03(Model model){
    
    
        model.addAttribute("msg", "重定向");
        return "redirect:/index.jsp";
    }

}

3.4 接受请求参数以及回显

  • 提交的域名称和处理方法的参数名一致就可以直接接收

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

    • 可以在参数前加@RequestParam(“xxx”)优化,变成和域名称一致
    • 无论一样不一样,只要是接收前端数据的,都要写上
  • 提交的是一个对象,要求提交的表单域和对象的属性名一致,参数使用对象即可(对象需要又set方法)

测试

package edu.controller;

import edu.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/user")
public class UserController {
    
    
    /*
    * 提交的域名称和处理方法的参数名一致就可以直接接收
    * */
    @RequestMapping("/t1")
    public String test01(String name, Model model){
    
    
        model.addAttribute("msg", name);
        return "hello";
    }

    /*
    * 提交的域名称和处理方法的参数名不一致
    * */
    @RequestMapping("/t2")
    public String test02(@RequestParam("names") String name, Model model){
    
    
        model.addAttribute("msg", name);
        return "hello";
    }

    /*
    * 前端提交了一个对象
    * 传递的是个对象,匹配user中的字段名,名字一致就可以
    * */
    @RequestMapping("/t3")
    public String test02(User user, Model model){
    
    
        model.addAttribute("msg", user.toString());
        return "hello";
    }
}

3.4.1 数据回显到前端

  • 通过ModelAndView (显示实现controller接口时常用)
  • 通过Model (使用controller注解时常见)
  • 通过ModelMap (继承了LinkedHashMap)

3.5 乱码问题

springmvc给我们提供了一个解决乱码的过滤器,直接在web.xml中进行配置即可

<!--乱码过滤器-->
<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>

3.6 JSON

什么是JSON

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

前后端分离

  • 后端部署后端,提供接口,提供数据
  • 前端独立部署,负责渲染后端的数据
  • json作为前后端数据交换的格式

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

  • 对象表示为键值对,数据由逗号分隔
  • 花括号保存对象
  • 方括号保存数组
{"name", "kuquan"}
{"age", "18"}
{"sex", "man"}

json和js对象可以很容易的相互转化

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <script>
        // 编写js对象
        var user = {
      
      
            name: "kuquan",
            age: "3",
            sex: "man"
        };

        // 将js对象转换为json对象
        var json = JSON.stringify(user);
        
        // 将json对象转换成一个字符串
        var obj = JSON.parse(json);

        console.log(json)
        console.log(obj)
    </script>

</head>
<body>

</body>
</html>
  • 效果

3.7 Controller返回json对象

  • jackson应该是目前比较好的json解析工具了
  • 当然工具不止一个,比如还有阿里巴巴的fastjson等等
  • 我们使用jackson需要导入jar包
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>

jackson

  • 测试.objectMapper将字符串封装成json格式
package edu.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.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 {
    
    

    /*@ResponseBody
    * 加上这就,就不会走视图解析器,直接返回字符串
    * */
    @ResponseBody
    @RequestMapping("/json1")
    public String json1() throws JsonProcessingException {
    
    
        User user = new User("余生", 18, "man");

        // jackson  objectMapper
        ObjectMapper objectMapper = new ObjectMapper();

        String value = objectMapper.writeValueAsString(user);

        return value;
    }
}
  • 结果

在这里插入图片描述

此时格式正确了,但是出现了乱码

解决方案

  • 修改requestmapper为@RequestMapping(value = "/json1", produces = "application/json;charset=utf-8")

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-paxB3AYH-1633245411554)(狂神说springmvc.assets/image-20211002111750760.png)]

  • springmvc提供了统一的乱码解决方案
<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>

3.7.1**@RestController** and @ResponseBody

  • @RestController类上如果加这样的标签,则都不会调用视图解析器,只会返回一个字符串
  • @ResponseBody方法加上这就,就不会走视图解析器,直接返回字符串

3.7.2 返回多个对象时

@ResponseBody
@RequestMapping("/json2")
public String json2() throws JsonProcessingException {
    
    
    User user1 = new User("余生", 18, "man");
    User user2 = new User("苦泉", 18, "man");

    List<User> list = new ArrayList<>();
    list.add(user1);
    list.add(user2);

    return new ObjectMapper().writeValueAsString(list);
}

结果

在这里插入图片描述

objectmapper解析时间后的默认格式为timestamp(从1901-1-1到现在的毫秒数)

如何转化为可视化的时间?

  • 使用simpledateformat格式化时间然后再传给objectmapper

3.7.3 封装一个json工具类

package edu.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.text.SimpleDateFormat;

public class JsonUtils {
    
    
    public static String getJson(Object o) throws JsonProcessingException {
    
    
        return getJson(o, "yyyy-MM-dd");
    }

    public static String getJson(Object o, String format) throws JsonProcessingException {
    
    
        ObjectMapper objectMapper = new ObjectMapper();

        /*
         * 关闭默认使用时间戳
         * */
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

        /*
         * 格式化
         * */
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        objectMapper.setDateFormat(simpleDateFormat);

        return objectMapper.writeValueAsString(o);
    }
}


3.7.4 FastJson

阿里巴巴开发的专门用于java开发的包,方便实现json对象与json的转换.

4.整合ssm

  • idea 2021.1.1
  • mysql 5.5
  • tomcat 9.0.19
  • maven 3.6.3

4.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,'从进门到进牢');
  • 导入依赖
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.20</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.0</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.6</version>
    </dependency>

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.35</version>
    </dependency>

    <!--数据库连接池:c3p0-->
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.2</version>
    </dependency>

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

</dependencies>
  • maven资源导出问题
<!--在build中配置resources,来防止我们资源导出失败的问题-->
<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>
  • 配置db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=UTF-8
jdbc.username=xxx
jdbc.password=xxx
  • 配置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>

    <settings>
        <!--日志-->
        <!--日志同一时间只能使用一个-->
        <!--标准日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--LOG4J日志-->
        <!--<setting name="logImpl" value="LOG4J"/>-->

        <!--将经典数据库命名转化为驼峰命名-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>

        <!--开启全局缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>

    <!--另一种方式-->
    <!--<properties resource="org/mybatis/example/config.properties">
        <property name="username" value="dev_user"/>
        <property name="password" value="F2Fa3!33TYyg"/>
    </properties>-->

    <!--可以给实体类写别名-->
    <typeAliases>
        <!--给具体的类起别名-->
        <!--<typeAlias alias="User" type="bean.User"/>-->

        <!--如果有bean类使用@Alias()注释,需要将相应的包在这里导入-->
        <package name="edu.pojo"/>
    </typeAliases>

    <!--绑定接口-->
    <mappers>
        <!--接口需要和配置文件(xml)同名-->
        <!--class注册方式:mapper文件需要放在resources/dao文件夹下-->
        <!--<mapper class="dao.UserDao"></mapper>-->
        <!--rsource注册方式:xml文件需要放在resources/dao文件夹下 or mapper.xml文件和mapper处在同一个包下-->
        <!--<mapper resource="dao/UserMapper.xml"></mapper>-->
        <!--<mapper resource="dao/BlogMapper.xml"></mapper>-->
        <mapper class="edu.mapper.BookMapper"></mapper>
    </mappers>


</configuration>

数据源委托给了spring来管理,mybatis主要用来配置<settings>and<mappers>and<typeAliases>

  • spring-dao层
<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://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/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--开启注解支持-->
    <context:annotation-config></context:annotation-config>

    <!--关联数据库配置文件-->
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>

    <!--DataSource:数据源 c3p0 dbcp  druid hikari-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"></property>
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <!--c3p0的私有属性-->
        <property name="maxPoolSize" value="30"></property>
        <property name="minPoolSize" value="10"></property>
        <!--关闭连接后不自动提交-->
        <property name="autoCommitOnClose" value="false"></property>
        <!--获取连接的超时时间-->
        <property name="checkoutTimeout" value="10000"></property>
        <!--获取连接失败的重试次数-->
        <property name="acquireRetryAttempts" value="3"></property>
    </bean>

    <!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--绑定mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
    </bean>

    <!--配置dao接口扫描包,动态实现dao接口可以注入到spring容器中-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--注入sqlSessionFactoryBeanName-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
        <!--扫描的包-->
        <property name="basePackage" value="edu.mapper"></property>
    </bean>

    <!--SqlSessionTemplate:就是我们使用的sqlSession-->
    <!--<bean id="selSession" class="org.mybatis.spring.SqlSessionTemplate">
        &lt;!&ndash;只能使用构造器注入sqlSessionFactory,因为没有set方法&ndash;&gt;
        <constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
    </bean>-->


</beans>
  • spring-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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://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/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--开启注解支持-->
    <context:annotation-config></context:annotation-config>

    <!--扫描service下的包-->
    <context:component-scan base-package="edu.service"></context:component-scan>

    <!--将所有业务类注入到spring容器中-->
    <!--使用注解-->


    <!--声明式事务-->
    <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--AOP事务支持-->
    <!--配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="dataSource"></constructor-arg>
    </bean>

    <!--结合AOP实现事务织入-->
    <!--配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--给哪些方法配置事务-->
        <!--配置事务的传播特性  propagation-->
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED"></tx:method>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut id="txpointcut" expression="execution(* edu.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txpointcut"></aop:advisor>
    </aop:config>

</beans>
  • spring-web

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!--dispatcherservlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--DispatcherServlet要绑定springmvc的配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:application.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>

    <!--乱码过滤-->
    <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>

    <!--默认sessoin过期时间-->
    <session-config>
        <session-timeout>15</session-timeout>
    </session-config>

</web-app>

spring-web.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
        https://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">

    <!--开启注解支持-->
    <context:annotation-config></context:annotation-config>

    <!--扫描包-->
    <context:component-scan base-package="edu.controller"></context:component-scan>

    <!--让springmvc不处理静态资源-->
    <mvc:default-servlet-handler></mvc:default-servlet-handler>

    <!--自动配置映射器和适配器-->
    <mvc:annotation-driven>
        <!--json乱码问题解决-->
        <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>

    <!--配置视图解析器  *模板引擎 Thymeleaf freemarker*
        1.获取ModelAndView的数据
        2.解析ModelAndView的视图名字
        3.拼接视图名字,找到对应的视图
        4.将数据渲染到这个视图上
    -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <!--后缀-->
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!--BeanNameUrlHandlerMapping:bean  handler-->


</beans>

至此,环境配置基本结束

4.2 业务代码

pojo包

Books

package edu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.ibatis.type.Alias;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Alias("books")
public class Books {
    
    
    private int bookID;
    private String bookName;
    private int bookCounts;
    private String detail;
}

mapper

bookmapper

package edu.mapper;

import edu.pojo.Books;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;
import java.util.Map;

public interface BookMapper {
    
    
    /*
    * 增加一本书
    * */
    @Insert("insert into books values(null,#{bookName},#{bookCounts},#{detail})")
    public int addOneBook(Books books);

    /*
    * 删除一本书
    * */
    @Delete("delete from books where bookID=#{id}")
    public int delBookByID(@Param("id") int id);

    /*
    * 更新一本书
    * */
    public int updateBook(Books books);

    /*
    * 根据id查询一本书
    * */
    @Select("select * from books where bookID=#{id}")
    public Books queryByID(@Param("id") int id);

    /*
    * 查询所有书籍
    * */
    @Select("select * from books")
    public List<Books> queryAllBooks();

    /*
    * 根据书名关键字查询书籍
    * */
    @Select("select * from books where bookName like #{key}")
    public List<Books> queryBookLike(@Param("key") String key);
}

bookmapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--xxx:接口的全路径-->
<mapper namespace="edu.mapper.BookMapper">
    <!--在当前xml中使用二级缓存-->
    <cache></cache>

    <update id="updateBook" parameterType="books">
        update books set bookName=#{bookName},bookCounts=#{bookCounts},detai=#{detail} where bookID=#{bookID}
    </update>

</mapper>

service

userservice

package edu.service;

import edu.pojo.Books;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface BookService {
    
    
    /*
     * 增加一本书
     * */
    public int addOneBook(Books books);

    /*
     * 删除一本书
     * */
    public int delBookByID(int id);

    /*
     * 更新一本书
     * */
    public int updateBook(Books books);

    /*
     * 根据id查询一本书
     * */
    public Books queryByID(int id);

    /*
     * 查询所有书籍
     * */
    public List<Books> queryAllBooks();

    /*
     * 根据书名关键字查询书籍
     * */
    public List<Books> queryBookLike(@Param("key") String key);
}

userserviceimpl

package edu.service;

import edu.mapper.BookMapper;
import edu.pojo.Books;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class BookServiceImpl implements BookService{
    
    

    /*
    * service调用dao层
    * */

    @Autowired
    @Qualifier("bookMapper")
    private BookMapper bookMapper;

    public void setBookMapper(BookMapper bookMapper) {
    
    
        this.bookMapper = bookMapper;
    }

    @Override
    public int addOneBook(Books books) {
    
    
        return bookMapper.addOneBook(books);
    }

    @Override
    public int delBookByID(int id) {
    
    
        return bookMapper.delBookByID(id);
    }

    @Override
    public int updateBook(Books books) {
    
    
        return bookMapper.updateBook(books);
    }

    @Override
    public Books queryByID(int id) {
    
    
        return bookMapper.queryByID(id);
    }

    @Override
    public List<Books> queryAllBooks() {
    
    
        return bookMapper.queryAllBooks();
    }

    @Override
    public List<Books> queryBookLike(String key) {
    
    
        return bookMapper.queryBookLike(key);
    }
}

controller

usercontroller

package edu.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import edu.pojo.Books;
import edu.service.BookService;
import edu.utils.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

@Controller
@RequestMapping("/book")
public class BookController {
    
    

    @Autowired
    @Qualifier("bookServiceImpl")
    private BookService bookService;

    public void setBookService(BookService bookService) {
    
    
        this.bookService = bookService;
    }

    @ResponseBody
    @RequestMapping("/allbooks")
    public String getAllBooks() throws JsonProcessingException {
    
    
        List<Books> booksList = bookService.queryAllBooks();
        return JsonUtils.getJson(booksList);
    }

    @ResponseBody
    @RequestMapping("/getbook/{id}")
    public String getBooksByID(@PathVariable int id) throws JsonProcessingException {
    
    
        Books books = bookService.queryByID(id);
        return JsonUtils.getJson(books);
    }

    @ResponseBody
    @RequestMapping("/addbook/{bookName}/{bookCounts}/{detail}")
    public String insertBook(Books books) throws JsonProcessingException {
    
    
        int i = bookService.addOneBook(books);
        System.out.println(i);
        return JsonUtils.getJson(books);
    }

    @ResponseBody
    @RequestMapping("/delbook/{id}")
    public String delBook(@PathVariable int id) throws JsonProcessingException {
    
    
        int i = bookService.delBookByID(id);
        System.out.println(i);
        return JsonUtils.getJson(id);
    }

    @ResponseBody
    @RequestMapping("/querybook/{str}")
    public String queryBook(@PathVariable String str) throws JsonProcessingException {
    
    
        List<Books> booksList = bookService.queryBookLike("%" + str + "%");
        return JsonUtils.getJson(booksList);
    }
}

url采用restful格式



4.3 测试

  • querybook

在这里插入图片描述

  • allbooks
    在这里插入图片描述

  • /getbook/{id}

在这里插入图片描述




5.springmvc拦截器

springmvc的拦截器自带静态资源过滤,只拦截controller

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

  • 过滤器是servlet规范的一部分,任何javaweb工程都可以使用
  • 在url-pattern中配置/*后,可以对所有要访问的资源进行拦截
  • 拦截器是springmvc框架自己的,只有使用了sprinmvc框架的工程才能用
  • 拦截器只会拦截访问的控制器方法,如果访问的jsp/html等静态资源是不会拦截的

5.1 如何自定义拦截器

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

一个自定义拦截器

package edu.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 {
    
    

    /*
    * 过滤的执行函数
    * */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        System.out.println("before interceptor");

        // true:放行  false:不放行
        return true;
    }

    /*
    * 做日志操作
    * */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
    
        System.out.println("after interceptor");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
    
        System.out.println("clear interceptor");
    }
}

在配置文件中添加配置

<!--拦截器配置组-->
<mvc:interceptors>
    <!--**代表所有的内容-->
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="edu.config.MyInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

猜你喜欢

转载自blog.csdn.net/qq_45826803/article/details/120594898