SpringMVC

1、回顾MVC

(1) Model(模型层)
角色:处理数据和业务逻辑的“秘书”。

包含内容:

  • POJO/Bean/Domain:数据实体类,描述业务对象。

  • Service:实现核心业务逻辑(如用户注册、订单处理)。

  • Dao(Data Access Object数据库访问对象):负责数据持久化操作(如数据库增删改查)。

职责:

  • 封装业务逻辑和数据操作。

  • 独立于视图和控制器,确保数据一致性。

(2) View(视图层)
角色:负责展示数据的“秘书”。

常见技术:JSP、Thymeleaf、HTML、Freemarker 等。

职责:

  • 接收来自控制器的数据,渲染用户界面。

  • 被动展示:避免包含业务逻辑,仅处理显示逻辑(如数据格式化)。

(3) Controller(控制器层)
角色:协调调度的“司令官”。

职责:

  • 接收用户请求(如HTTP请求)。

  • 调用Model处理业务逻辑(如调用Service层)。

  • 根据处理结果选择合适的视图进行渲染。

  • 控制流程,但不直接处理数据或展示逻辑。

2、第一个SpringMVC

  1. 导入依赖

    <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.2.0.RELEASE</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>
    
  2. 导入web支持(ctrl+N快速搜索)

    在这里插入图片描述

  3. web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
             version="6.0">
        <!--1.注册DispatcherServlet-->
        <servlet>
            <servlet-name>springmvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc-servlet.xml</param-value>
            </init-param>
            <!--启动级别-1-->
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <!--/ 匹配所有的请求;(不包括.jsp)-->
        <!--/* 匹配所有的请求;(包括.jsp)-->
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    
  4. springmvc-servlet.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        
         <!--   处理器映射器 -->
        <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
        <!--   处理器适配器 -->
        <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
    
        <!--视图解析器:DispatcherServlet给他的ModelAndView-->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
            <!--前缀-->
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <!--后缀-->
            <property name="suffix" value=".jsp"/>
        </bean>
    
        <!--Handler-->
        <bean id="/hello" class="zhao.yuan.controller.HelloController"/>
    </beans>
    
  5. HelloController

    public class HelloController implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
            //ModelAndView 模型和视图
            ModelAndView mv = new ModelAndView();
    
            //封装对象,放在ModelAndView中。Model
            mv.addObject("msg","HelloSpringMVC!");
            //封装要跳转的视图,放在ModelAndView中
            mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp
            return mv;
        }
    }
    
    
  6. hello.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
        <head>
            <title>Title</title>
        </head>
        <body>
            ${msg}
        </body>
    </html>
    
  7. 遇到的问题:404

    在这里插入图片描述

    加入所有的包(如果项目包过多,从右侧maven中查看对应依赖并引入,全部引入tomcat会报错)

在这里插入图片描述

3、SpringMVC运行原理

  • **DispatcherServlet:**前端控制器
  • HandlerMapping: 处理器映射器
  • HandlerAdapter: 处理器适配器
  • viewResolver: 视图解析器

在这里插入图片描述

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

  1. 先申请一个DispatcherServlet,将url传给HandlerMapping
  2. HandlerMapping根据url查找到具体的Handler(即Controller)(比如说上面代码中的/hello)
  3. HandlerExecution解析Handler将信息传递给DispatcherServlet
  4. HandlerAdapter根据DispatcherServlet传递的Handler寻找到对应的适配处理器调用(SpringMVCHandler有多种实现方式(Controller,HttpRequestHandler,Servlet等))
  5. Handler由具体的Controller执行
  6. Controller将具体的执行信息返回给HandlerAdapter(如:ModelAndView)
  7. HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet
  8. DispatcherServlet调用ViewResolver解析信息
  9. ViewResolver将解析好的信息返回给DispatcherServlet
  10. DispatcherServlet根据解析好的信息调用具体的视图

4、使用注解开发SpringMVC

  1. web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
        <!--1.注册servlet-->
        <servlet>
            <servlet-name>springMVC</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!--通过初始化参数指定SpringMVC配置文件的位置,进行关联-->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc-servlet.xml</param-value>
            </init-param>
            <!-- 启动顺序,数字越小,启动越早 -->
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>springMVC</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    
  2. springmvc-servlet.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           https://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/mvc
           https://www.springframework.org/schema/mvc/spring-mvc.xsd">
        <!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
        <context:component-scan base-package="com.zhao.controller"/>
        <!-- 让Spring MVC不处理静态资源 -->
        <mvc:default-servlet-handler/>
        <!--
      支持mvc注解驱动
      在spring中一般采用@RequestMapping注解来完成映射关系
      要想使@RequestMapping注解生效
      必须向上下文中注册DefaultAnnotationHandlerMapping
      和一个AnnotationMethodHandlerAdapter实例
      这两个实例分别在类级别和方法级别处理。
      而annotation-driven配置帮助我们自动完成上述两个实例的注入。
      -->
        <mvc:annotation-driven/>
        <!-- 视图解析器 -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <property name="suffix" value=".jsp"/>
        </bean>
    </beans>
    
  3. HelloController

    package com.zhao.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    @RequestMapping("/helloController")
    public class HelloController {
        @RequestMapping("/hello")
        public String hello(Model model){
            model.addAttribute("msg","HelloSpringMVC!");
            return "hello";
        }
    }
    
  4. jsp

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

5、RestFul风格

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

功能
资源:互联网所有的事物都可以被抽象为资源
资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
分别对应 添加、 删除、修改、查询。

例如:
/order/1 HTTP GET :得到 id = 1 的 order
/order/1 HTTP DELETE:删除 id = 1的 order
/order HTTP PUT:更新 order
/order HTTP POST:新增 orde

5.1、RequestMapping,GetMapping,PostMapping注解

  • SpringMVC 使用@RequestMapping 注解为控制器指定可以处理哪些 URL 请求
  • 在控制器的类定义及方法定义处都可标注 @RequestMapping
    • 标记在类上:提供初步的请求映射信息。相对于 WEB 应用的根目录
    • 标记在方法上:提供进一步的细分映射信息。相对于标记在类上的 URL。
GetMapping注解等价于RequestMapping(value="/test",method=RequestMethod.GET)
PostMapping注解等价于RequestMapping(value="/test",method=RequestMethod.POST)

5.2、PathVariable注解

通过 @PathVariable 可以将 URL中占位符参数绑定到控制器处理方法的参数中:URL 中的 {xxx} 占位符可以通过 @PathVariable(“xxx”) 绑定到操作方法的入参中。

//@PathVariable 注解可以将请求 URL 路径中的请求参数,传递到处理请求方法的入参中
//http://localhost:8080/add/1/3
    @PostMapping("/add/{a}/{b}")
    public String test3(@PathVariable int a,@PathVariable String b, Model model){
        String res = a + b;
        model.addAttribute("msg","结果2为"+res);
        return "test";
    }

6、数据处理与跳转

除了使用视图解析器进行跳转外,还可以使用forward,redirect进行页面跳转

6.1、重定向与转发

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    
    <!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
    <context:component-scan base-package="com.zhao.controller"/>
    <!-- 让Spring MVC不处理静态资源 -->
    <mvc:default-servlet-handler/>
    <mvc:annotation-driven/>
    <!-- 注释掉视图解析器 -->
    <!--<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>-->
</beans>
package com.zhao.controller;

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

@Controller
@RequestMapping("/helloController")
public class HelloController {
    @RequestMapping("/hello")
    public String hello(Model model){
        model.addAttribute("msg","HelloSpringMVC!");
        //转发
        return "forward:/WEB-INF/jsp/hello.jsp";
    }
    
    @RequestMapping("/hello1")
    public String hello(Model model){
        model.addAttribute("msg","HelloSpringMVC1!");
        //重定向(访问不到WEB-INF下的内容)
        return "redirect:/index.jsp";
    }
}

6.2、数据处理

  1. 参数传递基本数据类型和String时,参数名与请求参数名字一样时,会自动映射

    @Controller
    @RequestMapping("/user")
    public class UserController {
    
        @GetMapping("/t1")
        // url: /user/t1?name=xxx  
        public String test1(String name, Model model){
            // 1. 接收前端参数
            System.out.println("接收到前端的参数为"+name);
    
            // 2. 将返回的结果传递纷前端, Model
            model.addAttribute("msg",name);
    
            // 3. 视图跳转
            return "test";
        }
    }
    
  2. 参数传递对象时,对象属性名与请求参数名字一样时,才会自动映射

    @Data
    public class User{
    	private String name;
    	private int age;
    }
    
    @Controller
    @RequestMapping("/user")
    public class UserController {
    
        @GetMapping("/t2")
        // url: /user/t2?name1=zhangsan&age=18  
        public String test1(User user){
            System .out.println(user)
            return "test";
        }
    }
    >>User(name=null,age=18)
    

6.3、@RequestParam

指定请求参数名称

@Controller
@RequestMapping("/user")
public class UserController {

    @GetMapping("/t1")
    // url: /user/t1?username=xxx  参数不一致
    public String test1(@RequestParam("username") String name, Model model){
        // 1. 接收前端参数
        System.out.println("接收到前端的参数为"+name);

        // 2. 将返回的结果传递纷前端, Model
        model.addAttribute("msg",name);

        // 3. 视图跳转
        return "test";
    }
}

6.4、注解RequestParam与Param的联系

@RequestParam@Param 是两个在不同框架中用于处理参数的注解,它们之间没有直接的继承或实现关系,但在功能上都与"参数绑定"相关。

特性 @RequestParam @Param
所属框架 Spring MVC / Spring Web MyBatis 或 Spring Data JPA
使用位置 Controller层方法参数 Mapper/Dao层方法参数
核心作用 指定请求参数名称 为SQL语句中的参数起别名

6.5、乱码处理

  1. 可以用Springmvc自带的过滤器

    <filter>
        <filter-name>filter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
  2. 自带的无法解决用自定义的过滤器

    package com.zhao.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.nio.charset.StandardCharsets;
    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 final 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++) {
                                // 处理get乱码
                                values[i] = new String(values[i]
                                        .getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                            }
                        }
                    }
                    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;
        }
    }
    
    <?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>
        <welcome-file-list>
            <welcome-file>form.jsp</welcome-file>
        </welcome-file-list>
        <filter>
            <filter-name>filter</filter-name>
            <filter-class>com.zhao.filter.GenericEncodingFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    </web-app>
    

    测试:

    form.jsp

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

    Controller

    @Controller
    
    public class HelloController {
        @PostMapping("/h/hello")
        public String hello(String name,Model model){
            System.out.println("name = " + name);
            model.addAttribute("msg",name);
            return "hello";
        }
    }
    

    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>
        <welcome-file-list>
            <welcome-file>form.jsp</welcome-file>
        </welcome-file-list>
        <filter>
            <filter-name>filter</filter-name>
            <filter-class>com.zhao.filter.GenericEncodingFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>filter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    </web-app>
    

7、@ResponseBody与@RestController

@ResponseBody标注后return “test”不会走视图解析器,返回字符串

@RestController等同于@Controller加@ResponseBody

8、Json

Json在js中是用Json类来进行字符串与Json之间的转换,在java中需要使用工具类

8.1、Jackson Databind依赖

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.20.0</version>
</dependency>
package com.zhao.pojo;

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

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String name;
    private int age;
    private String sex;
}
package com.zhao.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhao.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {

    @RequestMapping("/user")
    @ResponseBody
    public String json() throws JsonProcessingException {
        //创建一个jackson的对象映射器,用来解析数据
        ObjectMapper objectMapper = new ObjectMapper();
        User user = new User("张三", 18, "男");
        //将我们的对象解析成为json格式
        String s = objectMapper.writeValueAsString(user);
        return s;
    }
}

8.2、解决json乱码

  1. 单个方法解决
@RequestMapping(value = "/user",produces = "application/json;charset=utf-8" )
  1. 全局解决:springmvc-servlet.xml
<mvc:annotation-driven>
  <mvc:message-converters register-defaults="true">
    <bean class="org.springframework.http.converter.StringHttpMessageConverter">
      <constructor-arg value="UTF-8"/>
    </bean>
    <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
      <property name="objectMapper">
        <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
          <property name="failOnEmptyBeans" value="false"/>
        </bean>
      </property>
    </bean>
  </mvc:message-converters>
</mvc:annotation-driven>

8.3、json的各种返回形式

8.3.1、集合返回多个对象
@RequestMapping(value = "/user1")
    @ResponseBody
    public String json1() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        ArrayList<User> list = new ArrayList<>();
        User user = new User("张三", 18, "男");
        User user1 = new User("张三", 18, "男");
        User user2 = new User("张三", 18, "男");
        User user3 = new User("张三", 18, "男");
        list.add(user);
        list.add(user1);
        list.add(user2);
        list.add(user3);
        String s = objectMapper.writeValueAsString(list);
        return s;
    }
8.3.2、返回时间
//显示出来是时间戳
@RequestMapping(value = "/user2")
    @ResponseBody
    public String json2() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        Date date = new Date();
        String s = objectMapper.writeValueAsString(date);
        return s;
    }
  1. 纯java解决显示真正时间
@RequestMapping(value = "/user2")
    @ResponseBody
    public String json2() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String s = objectMapper.writeValueAsString(simpleDateFormat.format(date));
        return s;
    }
  1. 使用Jackson带的方法

    @RequestMapping(value = "/user3")
        @ResponseBody
        public String json3() throws JsonProcessingException {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
    
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            objectMapper.setDateFormat(simpleDateFormat);
            Date date = new Date();
    
            String s = objectMapper.writeValueAsString(date);
            return s;
        }
    

8.4、提取出Json工具类

package com.zhao.utils;

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

import java.text.SimpleDateFormat;

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 simpleDateFormat){
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
        SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat(simpleDateFormat);
        objectMapper.setDateFormat(simpleDateFormat1);
        try {
            return objectMapper.writeValueAsString(object);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
@RequestMapping(value = "/user4")
@ResponseBody
public String json4() throws JsonProcessingException {
    return JsonUtils.getJson(new Date());
}

8.5、FastJson

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

<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>fastjson</artifactId>
   <version>2.0.59</version>
</dependency>
package com.blue.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.blue.pojo.User;

import java.util.ArrayList;
import java.util.List;

public class FastJsonDemo {
    public static void main(String[] args) {
        //创建一个对象
        User user1 = new User("秦疆1号", 3, "男");
        User user2 = new User("秦疆2号", 3, "男");
        User user3 = new User("秦疆3号", 3, "男");
        User user4 = new User("秦疆4号", 3, "男");
        List<User> list = new ArrayList<User>();
        list.add(user1);
        list.add(user2);
        list.add(user3);
        list.add(user4);

        System.out.println("*******Java对象 转 JSON字符串*******");
        String str1 = JSON.toJSONString(list);
        System.out.println("JSON.toJSONString(list)==>"+str1);
        String str2 = JSON.toJSONString(user1);
        System.out.println("JSON.toJSONString(user1)==>"+str2);

        System.out.println("\n****** JSON字符串 转 Java对象*******");
        User jp_user1=JSON.parseObject(str2,User.class);
        System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1);

        System.out.println("\n****** Java对象 转 JSON对象 ******");
        JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
        System.out.println("(JSONObject) JSON.toJSON(user2)==>"+jsonObject1.getString("name"));

        System.out.println("\n****** JSON对象 转 Java对象 ******");
        User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
        System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user);
    }
}	

9、ssm整合

9.1、创建数据库

CREATE DATABASE `ssmbuild`;

USE `ssmbuild`;

DROP TABLE IF EXISTS `books`;

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,'从进门到进牢');

9.2、pom.xml

<dependencies>
    <!--Junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <!--数据库驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.33</version>
    </dependency>
    <!-- 数据库连接池 -->
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.2</version>
    </dependency>

    <!--Servlet - JSP -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>

    <!--Mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.2</version>
    </dependency>

    <!--Spring-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.39</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
</dependencies>
<!--maven静态资源导出问题-->
<build>
    <finalName>springmvc-05-ssm</finalName>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

9.3、基本架构和配置文件

建立包结构

  • com.zhao.pojo
  • com.zhao.dao
  • com.zhao.service
  • com.zhao.controller

配置文件

  • mybatisConfig.xml
  • springConfig.xml
  • database.properties

mybatis-config.xml

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

springConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

database.properties

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

9.4、Mybatis

  1. pojo
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Books {

    private int bookID;
    private String bookName;
    private int bookCounts;
    private String detail;

}
  1. mapper
public interface BookMapper {

    // 增加一本书
    int addBook(Books books);

    // 删除一本书,booId和id不一样,所以用个注解转换
    int deleteBookById(@Param("bookId") int id);

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

    // 查询一本书
    Books queryBookById(@Param("bookId") int id);

    // 查询全部的书
    List<Books> queryAllBook();

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

<mapper namespace="com.zhao.mapper.BookMapper">
    
    <!--增加一个Book-->
    <insert id="addBook" parameterType="Books">
        insert into ssmbuild.books(bookName,bookCounts,detail)
        values (#{bookName}, #{bookCounts}, #{detail})
    </insert>
    
    <!--根据id删除一个Book-->
    <delete id="deleteBookById" parameterType="int">
        delete from ssmbuild.books where bookID=#{bookID}
    </delete>
    
    <!--更新Book-->
    <update id="updateBook" parameterType="Books">
        update ssmbuild.books
        set bookName = #{bookName},bookCounts = #{bookCounts},detail = #{detail}
        where bookID = #{bookID}
    </update>
    
    <!--根据id查询,返回一个Book-->
    <select id="queryBookById" resultType="Books">
        select * from ssmbuild.books
        where bookID = #{bookID}
    </select>
    
    <!--查询全部Book-->
    <select id="queryAllBook" resultType="Books">
        SELECT * from ssmbuild.books
    </select>

</mapper>
  1. service
public interface BookService {

    // 增加一本书
    int addBook(Books books);

    // 删除一本书,不是dao层,所以不用加注解@Para("bookId")
    int deleteBookById(int id);

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

    // 查询一本书
    Books queryBookById(int id);

    // 查询全部的书
    List<Books> queryAllBook();

}
public class BookServiceImpl implements BookService{

    // service调 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();
    }
}

9.5、Spring

  1. spring-dao.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd">
        
        <!-- 配置整合mybatis -->
        <!-- 1.关联数据库文件 -->
        <context:property-placeholder location="classpath:database.properties"/>
        
        <!-- 2.数据库连接池 -->
        <!--数据库连接池
            dbcp 半自动化操作 不能自动连接
            c3p0 自动化操作(自动的加载配置文件 并且设置到对象里面)
        -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <!-- 配置连接池属性 -->
            <property name="driverClass" value="${jdbc.driver}"/>
            <property name="jdbcUrl" value="${jdbc.url}"/>
            <property name="user" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
            
            <!-- c3p0连接池的私有属性 -->
            <property name="maxPoolSize" value="30"/>
            <property name="minPoolSize" value="10"/>
            <!-- 关闭连接后不自动commit -->
            <property name="autoCommitOnClose" value="false"/>
            <!-- 获取连接超时时间 -->
            <property name="checkoutTimeout" value="10000"/>
            <!-- 当获取连接失败重试次数 -->
            <property name="acquireRetryAttempts" value="2"/>
        </bean>
        
        <!-- 3.配置SqlSessionFactory对象 -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <!-- 注入数据库连接池 -->
            <property name="dataSource" ref="dataSource"/>
            <!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
            <property name="configLocation" value="classpath:mybatisConfig.xml"/>
        </bean>
        
        <!-- 4.配置扫描Dao接口包,动态实现Dao接口注入到spring容器中 -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <!-- 注入sqlSessionFactory -->
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
            <!-- 给出需要扫描Dao接口包 -->
            <property name="basePackage" value="com.zhao.mapper"/>
        </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">
        
        <!-- 1. 扫描service相关的bean -->
        <context:component-scan base-package="com.zhao.service" />
        
        <!--2. BookServiceImpl注入到IOC容器中-->
        <bean id="BookServiceImpl" class="com.zhao.service.BookServiceImpl">
            <property name="bookMapper" ref="bookMapper"/>
        </bean>
        
        <!-- 3. 配置事务管理器 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!-- 注入数据库连接池 -->
            <property name="dataSource" ref="dataSource" />
        </bean>
    
    </beans>
    
  3. springConfig.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <import resource="classpath:spring-dao.xml"/>
        <import resource="classpath:spring-service.xml"/>
        <import resource="classpath:spring-mvc.xml"/>
    </beans>
    

9.6、SpringMVC

  1. 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>
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <!--一定要注意:我们这里加载的是总的配置文件,之前被这里坑了!-->
          <param-value>classpath:springConfig.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>
    
      <!--乱码过滤 encodingFilter-->
      <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过期时间-->
      <session-config>
        <session-timeout>15</session-timeout>
      </session-config>
    
    </web-app>
    
  2. spring-mvc.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns: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
      https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    
      <!-- 配置SpringMVC -->
      <!-- 1.开启SpringMVC注解驱动 -->
      <mvc:annotation-driven />
      <!-- 2.静态资源默认servlet配置-->
      <mvc:default-servlet-handler/>
    
      <!-- 3.配置jsp 显示ViewResolver视图解析器 -->
      <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
      </bean>
    
      <!-- 4.扫描web相关的bean -->
      <context:component-scan base-package="com.zhao.controller" />
    
    </beans>
    

9.7、注意点

  1. 记得添加lib

  2. 问题:bean不存在(500)
    步骤:
    1、查看这个bean注入是否成功!(用注解判断)
    2、Junit单元测试,看我们的代码是否能够查询出来结果!

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
        BookService bookServiceImpl = context.getBean("BookServiceImpl", BookServiceImpl.class);
        List<Books> books = bookServiceImpl.queryAllBook();
        for (Books book : books) {
            System.out.println(book);
        }
    }
    

    3、问题,一定不在我们的底层,是spring出了问题!
    4、SpringMVC,整合的时候没调用到我们的service.层的bean

    springConfig.xml没有注入bean
    web.xml中,我们也绑定过配置文件!发现问题,我们配置的是Spring-mvc.Xml这里面确实没有service bean,所以报空指针
    所以,在web.xml中classpath:springConfig.xml而不是classpath:spring-mvc.xml

9.8、查询书籍

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>首页</title>
        <style>
            a{
                text-decoration: none;
                color: blue;
                font-size: 18px;
            }
            h3{
                width: 180px;
                height: 38px;
                margin: 100px auto;
                text-align: center;
                line-height: 38px;
                background: deepskyblue;
                border-radius: 5px;
            }
        </style>

    </head>
    <body>

        <h3>
            <a href="${pageContext.request.contextPath}/book/allBook">进入书籍页面</a>
        </h3>

    </body>
</html>

查找BootStrap CDN,搜索

<!-- 新 Bootstrap 核心 CSS 文件 -->

<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->

<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>

<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->

<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>

allbook.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>书籍展示</title>

        <!-- 新 Bootstrap 核心 CSS 文件 -->

        <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

        <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->

        <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>

        <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->

        <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    </head>
    <body>

        <div class="container">

            <div class="row clearfix">
                <div class="col-md-12 column">
                    <div class="page-header">
                        <h1>
                            <small>书籍列表 —— 显示所有书籍</small>
                        </h1>
                    </div>
                </div>
            </div>

            <div class="row clearfix">
                <div class="col-md-12 column">
                    <table class="table table-hover table-striped">
                        <thead>
                            <tr>
                                <th>书籍编号</th>
                                <th>书籍名字</th>
                                <th>书籍数量</th>
                                <th>书籍详情</th>
                                <th>操作</th>
                            </tr>
                        </thead>

                        <%-- 书籍从数据库中查询出来,从这个List中遍历出来:foreach --%>
                        <tbody>
                            <%--                <c:forEach var="book" items="${requestScope.get('list')}">--%>
                            <c:forEach var="book" items="${requestScope.get('list')}">
                                <tr>
                                    <td>${book.getBookID()}</td>
                                    <td>${book.getBookName()}</td>
                                    <td>${book.getBookCounts()}</td>
                                    <td>${book.getDetail()}</td>
                                </tr>
                            </c:forEach>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </body>
</html>

9.9、添加书籍

  1. allBook页面添加按钮

    <div class="row">
      <div class="col-md-4 column">
        <a class="btn btn-primary" href="${pageContext.request.contextPath}/book/toAddBook">新增书籍</a>
      </div>
    </div>
    
  2. Controller添加对应方法

    @RequestMapping("toAddBook")
    public String toAddBook(){
        return "addBook";
    }
    @RequestMapping("addBook")
    public String addBook(Books book){
        bookService.addBook(book);
        //用户刷新页面(F5)会导致表单重复提交,订单被多次保存。
        // 表单提交必须使用重定向,核心原因是防止重复提交和数据重复处理
        return "redirect:queryAll";
    }
    
  3. addBook页面

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

9.10、修改删除书籍

  1. allBook页面添加操作

    <tbody>
        <c:forEach var="book" items="${list}">
            <tr>
                <td>${book.bookID}</td>
                <td>${book.bookName}</td>
                <td>${book.bookCounts}</td>
                <td>${book.detail}</td>
                <td>
                    <a href="${pageContext.request.contextPath}/book/toUpdateBook/${book.bookID}">修改</a>
                    <a href="${pageContext.request.contextPath}/book/deleteBook/${book.bookID}">删除</a>
                </td>
            </tr>
        </c:forEach>
    
  2. Controller写相关方法

    //跳转到修改页面
    @RequestMapping("toUpdateBook/{bookID}")
    public String toUpdateBook(@PathVariable("bookID") int id,Model model){
        Books books = bookService.queryBookById(id);
        //        System.out.println(books);
        model.addAttribute("book",books);
        return "updateBook";
    }
    //修改
    @RequestMapping("updateBook")
    public String updateBook(Books books){
        //        System.out.println(books);
        bookService.updateBook(books);
        return "redirect:queryAll";
    }
    //删除
    @RequestMapping("deleteBook/{bookID}")
    public String deleteBook(@PathVariable("bookID") int id){
        bookService.deleteBookById(id);
        return "redirect:/book/queryAll";
    }
    
  3. updateBook页面

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
        <!-- 引入 Bootstrap -->
        <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
    </head>
    <body>
    <div class="container">
        <div class="row clearfix">
            <div class="col-md-12 column">
                <div class="page-header">
                    <h1>
                        <small>书籍列表-----修改书籍</small>
                    </h1>
                </div>
            </div>
        </div>
        <form action="${pageContext.request.contextPath}/book/updateBook" method="post">
            <!--隐藏域存id,将id传给后端执行sql-->
            <input type="hidden" name="bookID" value="${book.bookID}">
            <div class="form-group">
                <label>书籍名称:</label>
                <input type="text" name="bookName" class="form-control" value="${book.bookName}" required>
            </div>
            <div class="form-group">
                <label>书籍数量:</label>
                <input type="text" name="bookCounts" class="form-control" value="${book.bookCounts}" required>
            </div>
            <div class="form-group">
                <label>书籍详情:</label>
                <input type="text" name="detail" class="form-control"  value="${book.detail}" required>
            </div>
            <div class="form-group">
                <input type="submit" class="form-control" value="修改">
            </div>
        </form>
    </div>
    </body>
    </html>
    

9.11、搜索框模糊查询

  1. allbook页面添加搜索框表单

    <div class="row">
        <div class="col-md-4 column">
            <a class="btn btn-primary" href="${pageContext.request.contextPath}/book/toAddBook">新增书籍</a>
        </div>
        <div class="col-md-8 column" style="text-align: right">
            <form action="${pageContext.request.contextPath}/book/queryByBookName" method="post" class="form-inline">
                <label>
                    <input type="text" name="bookName" placeholder="请输入要查询书籍的名称" class="form-control">
                </label>
                <label>
                    <input type="submit" value="查询" class="btn btn-primary">
                </label>
            </form>
        </div>
    </div>
    
  2. Controller增加方法

    //根据书籍名称查询
    @RequestMapping("queryByBookName")
    public String queryBookByName(String bookName, Model model) {
        List<Books> books = bookService.queryBookByName(bookName);
        model.addAttribute("list", books);
        return "allBook";
    }
    
  3. service,mapper层添加

    @Override
    public List<Books> queryBookByName(String bookName) {
        if (bookName == null || bookName.equals("")){
            return bookMapper.queryAllBook();
        }
        return bookMapper.queryBookByName(bookName);
    }
    
    <select id="queryBookByName" resultType="com.zhao.pojo.Books">
        select * from ssmbuild.books where bookName like concat("%",#{bookName},"%")
    </select>
    

10、Ajax

  • AJAX 是一种不发生页面跳转、异步载入内容并改写页面内容的技术。
  • XMLHttpRequest对象是AJAX中非常重要的对象,所有的AJAX操作都是基于该对象的。
  • XMLHttpRequest对象用来封装请求报文,我们向服务器发送的请求信息全部都需要封装到该对象中。
  • jQuery 提供多个与 AJAX 有关的方法。
  • jquery常用的有 . a j a x (可以设置 p o s t 或 g e t ) , .ajax(可以设置post或get), .ajax(可以设置postget,.get,$.post三种
jQuery.ajax(...)
      部分参数:
            url:请求地址
            type:请求方式,GET、POST(1.9.0之后用method)
        	headers:请求头
            data:要发送的数据
    contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
          async:是否异步
        timeout:设置请求超时时间(毫秒)
      beforeSend:发送请求前执行的函数(全局)
        complete:完成之后执行的回调函数(全局)
        success:成功之后执行的回调函数(全局)
          error:失败之后执行的回调函数(全局)
        accepts:通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型
        dataType:将服务器端返回的数据转换成指定类型
          "xml": 将服务器端返回的内容转换成xml格式
          "text": 将服务器端返回的内容转换成普通文本格式
          "html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
        "script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
          "json": 将服务器端返回的内容转换成相应的JavaScript对象
        "jsonp": JSONP 格式使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数

10.1、入门

  1. 搭建springmvc框架,web.xml,spring-mvc.xml

  2. 导入jquery

  3. controller编写请求

    @RestController
    public class AjaxController {
        @RequestMapping("/ajax")
        public void ajax(String name, HttpServletResponse response) throws Exception {
            if ("admin".equals(name)) {
                response.getWriter().print("true");
            } else {
                response.getWriter().print("false");
            }
        }
    }
    
  4. 前端页面

    <!DOCTYPE html>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
        <script src="${pageContext.request.contextPath}/static/js/jquery-3.7.1.js"></script>
        <script>
            function a(){
                $.post({
                //所有参数:
                //url:将待载入也免得URL地址,json
                //data:待发送Key/value参数
                //success:载入成功时回调的函数
                //data封装了服务器返回的数据
                //status:状态
                    url:"${pageContext.request.contextPath}/ajax",
                    data:{"name":$("#name").val()},
                    success:function (data){
                        console.log(data);
                        console.log(status);
                    }
                })
            }
        </script>
    </head>
    <body>
    <p>跳转</p>
    <p>
    	<%--οnblur=""失去焦点产生事件--%>
        <input type="text" id="name" onblur="a()">
    </p>
    </body>
    </html>
    

10.2、Ajax异步加载数据

  1. User

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

    @RequestMapping("/a2")
        public List<User> a2(){
            ArrayList<User> list = new ArrayList<>();
            list.add(new User("张三",18,"男"));
            list.add(new User("张三",18,"男"));
            list.add(new User("张三",18,"男"));
            list.add(new User("张三",18,"男"));
            return list;
        }
    
  3. 页面显示

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
        <script src="${pageContext.request.contextPath}/static/js/jquery-3.7.1.js"></script>
        <script>
            $(function () {
                $("#btn").click(function () {
                    $.post({
                        url:"${pageContext.request.contextPath}/a2",
                        success:function (data){
                            console.log(data);
                            var html = "";
                            for (let i = 0; i < data.length; i++) {
                                html += "<tr>" +
                                    "<td>" + data[i].name + "</td>" +
                                    "<td>" + data[i].age + "</td>" +
                                    "<td>" + data[i].sex + "</td>" + "</tr>"
                            }
                            $("#tbody").html(html);
                        }
                    })
                })
            })
        </script>
    </head>
    <body>
    <input type="button" value="点击" id="btn">
    <table>
        <tr>
            <td>名字</td>
            <td>年龄</td>
            <td>性别</td>
        </tr>
        <tbody id="tbody">
    
        </tbody>
    </table>
    </body>
    </html>
    

10.3、Ajax表单验证

  1. Controller

    @RequestMapping("/a3")
    public String a3(String username,String pwd) {
        String msg = "";
        if (username != null) {
            if ("admin".equals(username)) {
                msg = "true";
            }else {
                msg = "error";
            }
        }
        if (pwd != null){
            if ("111".equals(pwd)) {
                msg = "true";
            }else {
                msg = "error";
            }
        }
    
        return msg;
    }
    
  2. login.jsp

    <html>
    <head>
        <title>Title</title>
        <script src="${pageContext.request.contextPath}/static/js/jquery-3.7.1.js"></script>
        <script>
            function a1() {
                $.post({
                    url:"${pageContext.request.contextPath}/a3",
                    data:{"username":$("#username").val()},
                    success:function (data){
                        console.log(data);
                        console.log(data.toString())
                        if (data.toString()=="true"){
                            $("#userInfo").css("color","green")
                        }else {
                            $("#userInfo").css("color","red")
                        }
                        $("#userInfo").html(data);
                    }
                })
            }
            function a2() {
                $.post({
                    url:"${pageContext.request.contextPath}/a3",
                    data:{"pwd":$("#pwd").val()},
                    success:function (data){
                        console.log(data);
                        console.log(data.toString())
                        if (data.toString()=="true"){
                            $("#pwdInfo").css("color","green")
                        }else {
                            $("#pwdInfo").css("color","red")
                        }
                        $("#pwdInfo").html(data);
                    }
                })
            }
    
        </script>
    </head>
    <body>
    
    <p>
        用户名:<input type="text" id="username" onblur="a1()">
        <span id="userInfo"></span>
    </p>
    <p>
        密 码:<input type="text" id="pwd" onblur="a2()">
        <span id="pwdInfo"></span>
    </p>
    </body>
    </html>
    

11、拦截器

11.1、基本使用

拦截器是AOP思想的具体应用,类似于过滤器Filter

过滤器

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

拦截器

只有使用了SpringMVC框架的工程才能使用

拦截器只会拦截控制器中的请求,如果访问jsp/html/js/css/image不会拦截

  1. 自定义拦截器实现HandlerInterceptor接口

    public class MyInterceptor implements HandlerInterceptor {
        //return true 放行,false 拦截
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("========执行前========");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("========执行后========");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("========清理========");
        }
    }
    
  2. spring-mvc.xml配置拦截器

    <!--拦截器配置-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--拦截所有请求,包括这个请求下的所有请求,/t/a/aa/aaa-->
            <mvc:mapping path="/**"/>
            <bean class="com.zhao.interceptor.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
    
  3. Controller

    @RestController
    public class InterceptorController {
        @RequestMapping("/i")
        public String interceptor(){
            System.out.println("InterceptorController执行了");
            return "ok";
        }
    }
    

    在这里插入图片描述

11.2、登录拦截

  1. login.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>用户登录</title>
    </head>
    <body>
    <div class="login-container">
        <h2>用户登录</h2>
        <form action="${pageContext.request.contextPath}/doLogin" method="post">
            <div class="form-group">
                <label for="username">用户名:</label>
                <input type="text" id="username" name="username" required>
            </div>
    
            <div class="form-group">
                <label for="password">密码:</label>
                <input type="password" id="password" name="password" required>
            </div>
    
            <div class="form-group">
                <button type="submit">登录</button>
            </div>
        </form>
    </div>
    </body>
    </html>
    
  2. success.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>用户仪表板</title></head>
    <body>
    <div class="dashboard-container">
        <div class="header">
            <h2>欢迎来到用户仪表板</h2>
            <div class="user-info">
                当前用户: <strong>${username}</strong>
                <a href="${pageContext.request.contextPath}/logout" class="logout-btn">退出登录</a>
            </div>
        </div>
    </div>
    </body>
    </html>
    
  3. Controller

    // 显示登录页面
        @RequestMapping(value = "/login")
        public String showLoginPage() {
            return "login";
        }
    
        // 处理登录请求
        @RequestMapping(value = "/doLogin", method = RequestMethod.POST)
        public String login(@RequestParam("username") String username,
                            @RequestParam("password") String password,
                            HttpServletRequest request,
                            Model model) {
    
            // 简单的用户验证(实际项目中应该查询数据库)
            if ("admin".equals(username) && "123456".equals(password)) {
                // 登录成功,将用户信息存入session
                HttpSession session = request.getSession();
                session.setAttribute("username", username);
                session.setAttribute("loginTime", System.currentTimeMillis());
    
                return "redirect:/success";
            } else {
                // 登录失败
                return "login";
            }
        }
    
        // 显示仪表板(需要登录才能访问)
        @RequestMapping(value = "/success", method = RequestMethod.GET)
        public String showDashboard(HttpServletRequest request, Model model) {
            HttpSession session = request.getSession();
            String username = (String) session.getAttribute("username");
            model.addAttribute("username", username);
            return "success";
        }
    
        // 退出登录
        @RequestMapping(value = "/logout", method = RequestMethod.GET)
        public String logout(HttpServletRequest request) {
            // 清除session
            HttpSession session = request.getSession();
            session.invalidate();
    
            return "redirect:/login";
        }
    
  4. 拦截器

    public class LoginInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 获取请求的URL
            String url = request.getRequestURI();
    
            // 登录页面和登录请求不拦截
            if (url.contains("/login") || url.contains("/doLogin")) {
                return true;
            }
    
            // 获取session
            HttpSession session = request.getSession();
            String username = (String) session.getAttribute("username");
    
            // 如果session中存在用户信息,则放行
            if (username != null && !username.isEmpty()) {
                return true;
            }
    
            // 不符合条件的,跳转到登录页面
            request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
            return false;
        }
    }
    
  5. 配置文件配置

    <!--拦截器配置-->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/login"/>
            <mvc:exclude-mapping path="/doLogin"/>
            <bean class="com.zhao.interceptor.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
    

12、文件上传

  1. 导入文件上传的jar包,commons-fileupload , Maven会自动帮我们导入他的依赖包 commons-io包;
 <dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.3</version>
 </dependency>
 <!--servlet-api导入高版本的-->
 <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
 </dependency>
  1. 配置bean:multipartResolver

    注意!!!这个bena的id必须为:multipartResolver , 否则上传文件会报400的错误!在这里栽过坑,教训!

    <!--文件上传配置-->
     <bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
        <property name="defaultEncoding" value="utf-8"/>
        <!-- 上传文件大小上限,单位为字节(10485760=10M) -->
        <property name="maxUploadSize" value="10485760"/>
        <property name="maxInMemorySize" value="40960"/>
     </bean>
    
  2. 编写前端页面

    <form action="/upload" enctype="multipart/form-data" method="post">
      <input type="file" name="file"/>
      <input type="submit" value="upload">
     </form>
    
  3. Controller

    @Controller
     public class FileController {
        //@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
        //批量上传CommonsMultipartFile则为数组即可
        @RequestMapping("/upload")
        public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
     
            //获取文件名 : file.getOriginalFilename();
            String uploadFileName = file.getOriginalFilename();
     
            //如果文件名为空,直接回到首页!
            if ("".equals(uploadFileName)){
                return "redirect:/index.jsp";
           }
            System.out.println("上传文件名 : "+uploadFileName);
     
            //上传路径保存设置
            String path = request.getServletContext().getRealPath("/upload");
            //如果路径不存在,创建一个
            File realPath = new File(path);
            if (!realPath.exists()){
                realPath.mkdir();
           }
            System.out.println("上传文件保存地址:"+realPath);
     
            InputStream is = file.getInputStream(); //文件输入流
            OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流
     
            //读取写出
            int len=0;
            byte[] buffer = new byte[1024];
            while ((len=is.read(buffer))!=-1){
                os.write(buffer,0,len);
                os.flush();
           }
            os.close();
            is.close();
            return "redirect:/index.jsp";
       }
     }
    

    采用file.Transto 来保存上传的文件

    @RequestMapping("/upload2")
     public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
     
        //上传路径保存设置
        String path = request.getServletContext().getRealPath("/upload");
        File realPath = new File(path);
        if (!realPath.exists()){
            realPath.mkdir();
       }
        //上传文件地址
        System.out.println("上传文件保存地址:"+realPath);
     
        //通过CommonsMultipartFile的方法直接写文件(注意这个时候)
        file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
     
        return "redirect:/index.jsp";
     }
    

13、文件下载

文件下载步骤:

1、设置 response 响应头

2、读取文件 – InputStream

3、写出文件 – OutputStream

4、执行操作

5、关闭流 (先开后关)

代码实现:

@RequestMapping(value="/download")
 public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
    //要下载的图片地址
    String  path = request.getServletContext().getRealPath("/upload");
    String  fileName = "基础语法.jpg";
 
    //1、设置response 响应头
    response.reset(); //设置页面不缓存,清空buffer
    response.setCharacterEncoding("UTF-8"); //字符编码
    response.setContentType("multipart/form-data"); //二进制传输数据
    //设置响应头
    response.setHeader("Content-Disposition",
            "attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));
 
    File file = new File(path,fileName);
    //2、 读取文件--输入流
    InputStream input=new FileInputStream(file);
    //3、 写出文件--输出流
    OutputStream out = response.getOutputStream();
 
    byte[] buff =new byte[1024];
    int index=0;
    //4、执行 写出操作
    while((index= input.read(buff))!= -1){
        out.write(buff, 0, index);
        out.flush();
   }
    out.close();
    input.close();
    return null;
 }

.exists()){
realPath.mkdir();
}
System.out.println(“上传文件保存地址:”+realPath);

       InputStream is = file.getInputStream(); //文件输入流
       OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流

       //读取写出
       int len=0;
       byte[] buffer = new byte[1024];
       while ((len=is.read(buffer))!=-1){
           os.write(buffer,0,len);
           os.flush();
      }
       os.close();
       is.close();
       return "redirect:/index.jsp";
  }
}

**采用file.Transto 来保存上传的文件**

```java
@RequestMapping("/upload2")
 public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
 
    //上传路径保存设置
    String path = request.getServletContext().getRealPath("/upload");
    File realPath = new File(path);
    if (!realPath.exists()){
        realPath.mkdir();
   }
    //上传文件地址
    System.out.println("上传文件保存地址:"+realPath);
 
    //通过CommonsMultipartFile的方法直接写文件(注意这个时候)
    file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
 
    return "redirect:/index.jsp";
 }

13、文件下载

文件下载步骤:

1、设置 response 响应头

2、读取文件 – InputStream

3、写出文件 – OutputStream

4、执行操作

5、关闭流 (先开后关)

代码实现:

@RequestMapping(value="/download")
 public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
    //要下载的图片地址
    String  path = request.getServletContext().getRealPath("/upload");
    String  fileName = "基础语法.jpg";
 
    //1、设置response 响应头
    response.reset(); //设置页面不缓存,清空buffer
    response.setCharacterEncoding("UTF-8"); //字符编码
    response.setContentType("multipart/form-data"); //二进制传输数据
    //设置响应头
    response.setHeader("Content-Disposition",
            "attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));
 
    File file = new File(path,fileName);
    //2、 读取文件--输入流
    InputStream input=new FileInputStream(file);
    //3、 写出文件--输出流
    OutputStream out = response.getOutputStream();
 
    byte[] buff =new byte[1024];
    int index=0;
    //4、执行 写出操作
    while((index= input.read(buff))!= -1){
        out.write(buff, 0, index);
        out.flush();
   }
    out.close();
    input.close();
    return null;
 }
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐