Java零基础——SpringMVC篇

news2024/9/27 23:26:03

1.SpringMVC介绍

SpringMVC是Spring框架中的一个组件,是一个轻量级的web的MVC框架,充当controller,其本质就是一个Servlet。

1.1 传统Servlet的不足

每个请求,都需要定义一个Servlet。虽然可以在service方法中,根据业务标识进行业务分发,但是每个Servlet中的service方法的实现是重复。如果想要对service进行更高层次的封装,就可以解决service的重复代码问题。

每个请求的参数,都需要根据request对象,从Map逐一的获取,单调且含量低。将所有的参数,自动封装映射,简化开发。

request.getParameter(“”)

每个Servlet,向客户端返回数据时,需要单独的处理。

request.getRequestDispatcher(“/路径”).forward(request,response)

Response.sendRedirect(“/路径”)

针对于Servlet在实际使用中的不便,Spring中提供了组件,SpringMVC,更进一步的简化了Servlet的开发。

1.2 SpringMVC的架构

在这里插入图片描述

1.2.1 DispatcherServlet
核心控制器,本质上就是一个Servlet,处理所有的客户端的请求。根据请求的资源路径,在处理器映射器中查找对应的处理器。

1.2.2 HandlerMapping
处理器映射器,存储所有当前程序中的处理器,如果在处理器映射器中查找不到资源路径,直接返回404。

1.2.3 HandlerAdapter
处理器适配器,用于适配各种处理器,调用具体的处理器程序。

1.2.4 Handler
具体处理器,开发者实现相应接口或者使用注解声明的程序。用于处理具体的请求。

1.2.5 ViewResolver
视图解析器,根据处理器返回的数据,进行数据处理,将数据处理成相应的格式。

JSP/JSON等等。

2.SpringMVC使用

2.1 SpringMVC入门使用

2.1.1 导入SpringMVC相关jar包

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

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>01-mvc01</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- 引入springmvc 相关jar包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
    </dependencies>
</project>

2.1.2 编写SpringMVC配置文件

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

    <!-- 配置了一个自定义的处理器 -->
    <bean id="controller01" name="/controller01.do"  class="com.bjpowernode.controller.Controller01"></bean>
    <bean id="controller02" name="/controller02.do"  class="com.bjpowernode.controller.Controller02"></bean>
    <!-- 开启springmvc 注解 -->
    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.*" />
    <!-- 开启springmvc 相关注解 -->
    <mvc:annotation-driven />
</beans>

2.1.3 编写相关类

package com.bjpowernode.controller;

import org.springframework.web.HttpRequestHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class Controller01 implements HttpRequestHandler {
    @Override
    public void handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
        System.out.println("你好啊 springmvc");
    }
}



package com.bjpowernode.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 Controller02 implements Controller {

    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("Hello SpringMVC  02");
        //模型视图
        //模型就是数据
        //视图 界面
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("name","Hello SpringMVC");
        modelAndView.setViewName("/index.html");//springmvc中 /表示当前项目
        return modelAndView;
    }
}



package com.bjpowernode.controller;

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

@Controller
@RequestMapping
public class Controller03 {

    @RequestMapping("hello1.do")
    public String hello(String name){
        System.out.println("name:"+name);
        System.out.println("你好springmvc");
        return "/index.html";
    }

    @RequestMapping("hello2.do")
    public String hello1(String name){
        System.out.println("name:"+name);
        System.out.println("你好springmvc");
        return "/index.html";
    }
}

2.1.4 在web.xml中配置SpringMVC

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <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.xml</param-value>
    </init-param>
    <!-- 配置服务器启动时 就初始化DispatcherServlet  -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

2.1.5 进行测试

使用bean标签的name属性进行访问。注意,每个名字必须有个/,如果多个名字,之间使用逗号。

2.2 SpringMVC的数据绑定

在SpringMVC中为了简化开发,SpringMVC对请求的参数进行预处理,SpringMVC支持按照参数名称,直接将请求参数封装传递给处理器中的方法,处理无需单独的获取。

2.2.1 请求参数
请求参数,是指基本数据类型和字符串、对象、数组、Map等。

2.2.2 获取请求参数

package com.bjpowernode.controller;

import com.bjpowernode.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/param")
public class ParamController {
    /**
     * 处理简单的参数
     * @return
     */
    @RequestMapping("/simple.do")
    public String doSimpleParam(Integer id,boolean flag,String name,@RequestParam("City") String city){
        System.out.println("id: "+id);
        System.out.println("flag: "+flag);
        System.out.println("name: "+name);
        System.out.println("city: "+city);
        return  "/success.html";//默认当做内部转发处理  默认当做视图路径
    }

    /**
     * 使用对象接收请求参数
     *      请求参数的名称 必须 和 对象中属性名一致  类型要支持转换
     * @param user
     * @return
     */
    @RequestMapping("/obj.do")
    public String objParam(User user){
        System.out.println("id: "+user.getId());
        System.out.println("flag: "+user.getFlag());
        System.out.println("name: "+user.getName());
        return  "/success.html";//默认当做内部转发处理  默认当做视图路径
    }

    /**
     * 使用map接收请求参数
     *  默认是不支持使用map集合接收数据  需要使用注解@RequestParam
     *  RequestParam :
     *      name/value : 绑定请求参数 ,默认根据名称注入值,当名称不一致,可以使用RequestParam设置对应的参数的名称,进行绑定
     *      required : 是否需要这个参数  默认true 如果有使用了RequestParam这个注解,默认必须传这个参数 如果不是必传 设置为 false
     *      defaultValue : 如果没有这个请求参数时或者请求参数值为null 设置默认值
     * @param param
     * @return
     */
    @RequestMapping("/map.do")
    public String mapParam(@RequestParam  Map<String,Object> param){
        System.out.println("id: "+param.get("id"));
        System.out.println("flag: "+param.get("flag"));
        System.out.println("name: "+param.get("name"));
        return  "/success.html";//默认当做内部转发处理  默认当做视图路径
    }

    @RequestMapping("/arr.do")
    public String arr(Integer id,boolean flag,String name,String[] likes){
        System.out.println("id: "+id);
        System.out.println("flag: "+flag);
        System.out.println("name: "+name);
        List<String> strings = Arrays.asList(likes);
        System.out.println(strings);
        return  "/success.html";//默认当做内部转发处理  默认当做视图路径
    }

    @RequestMapping("/list.do")
    public String arr(Integer id,boolean flag,String name,@RequestParam("likes") List<String> likes){
        System.out.println("id: "+id);
        System.out.println("flag: "+flag);
        System.out.println("name: "+name);
        System.out.println(likes);
        return  "/success.html";//默认当做内部转发处理  默认当做视图路径
    }
}

2.2.3 页面代码

<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>简单的数据</h1>
<form action="param/simple.do" method="get">
    <p>ID:<input name="id"  /></p>
    <p>boolean:<input name="flag" type="radio" value="true"  /><input name="flag" type="radio" value="false"  /></p>
    <p>String:<input name="name"  /></p>
    <p>city:<input name="City"  /></p>
    <input type="submit" value="提交" />
</form>
<h1>对象的数据</h1>
<form action="param/obj.do" method="get">
    <p>ID:<input name="id"  /></p>
    <p>boolean:<input name="flag" type="radio" value="true"  /><input name="flag" type="radio" value="false"  /></p>
    <p>String:<input name="name"  /></p>
    <input type="submit" value="提交" />
</form>
<h1>map的数据</h1>
<form action="param/map.do" method="get">
    <p>ID:<input name="id"  /></p>
    <p>boolean:<input name="flag" type="radio" value="true"  /><input name="flag" type="radio" value="false"  /></p>
    <p>String:<input name="name"  /></p>
    <input type="submit" value="提交" />
</form>
<h1>数组的数据</h1>
<form action="param/arr.do" method="get">
    <p>ID:<input name="id"  /></p>
    <p>boolean:<input name="flag" type="radio" value="true"  /><input name="flag" type="radio" value="false"  /></p>
    <p>String:<input name="name"  /></p>
    <p>likes:<input name="likes" type="checkbox" value="篮球"  />篮球<input name="likes" type="checkbox" value="足球"  />足球</p>
    <input type="submit" value="提交" />
</form>
<h1>list的数据</h1>
<form action="param/list.do" method="get">
    <p>ID:<input name="id"  /></p>
    <p>boolean:<input name="flag" type="radio" value="true"  /><input name="flag" type="radio" value="false"  /></p>
    <p>String:<input name="name"  /></p>
    <p>likes:<input name="likes" type="checkbox" value="篮球"  />篮球<input name="likes" type="checkbox" value="足球"  />足球</p>
    <input type="submit" value="提交" />
</form>
</body>
</html>

2.3 SpringMVC的跳转

在SpringMVC中,默认的跳转方式内部转发,,每个URL前面默认有forward:

,默认会将方法的返回值当做视图的路径处理。并且,在SpringMVC中,/表示当前项目根目录。如果想要使用重定向,则使用关键字:redirect:/路径。

2.3.1 代码示例

package com.bjpowernode.controller;

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

@Controller
@RequestMapping("jump")
public class JumpController {

    @RequestMapping("forward.do")
    public String forward(){
        System.out.println("内部转发跳转!");
        return  "forward:/success.html";
    }
    @RequestMapping("forward1.do")
    public String forward1(){
        System.out.println("内部转发跳转!");
        return  "/success.html";
    }

    @RequestMapping("redirect.do")
    public String redirect(){
        System.out.println("重定向跳转!");
        return  "redirect:/success.html";
    }
}

2.4 SpringMVC支持内置的对象

在SpringMVC中,支持为处理器中的方法注入内置的对象,如:HttpServletRequest、HttpServletResponse、HttpSession、Model等。

/**
 *
 * @param request
 * @param resp
 * @param session
 * @param model  是springmvc中 推荐使用参数传递的容器 当参数发生覆盖 优先使用model中的参数
 * @throws IOException
 */
@RequestMapping("servletParam.do")
public void servletParam(HttpServletRequest request, HttpServletResponse resp, HttpSession session, Model model) throws IOException {
    String name = request.getParameter("name");
    System.out.println(name);
    System.out.println(request);
    System.out.println(resp);
    System.out.println(session);
    System.out.println(model);
    resp.sendRedirect("success.html");
    //return "/success.html";
}

2.5 Spring+SpringMVC+Mybatis整合

2.5.1 创建项目导入jar包

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

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>02-mvc01</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <spring.version>5.2.0.RELEASE</spring.version>
</properties>
<dependencies>
    <!--servlet-api-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>
    <!-- jsp-api -->
    <dependency>
        <groupId>javax.servlet.html</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
    </dependency>
    <!-- jstl jar -->
    <dependency>
        <groupId>org.glassfish.web</groupId>
        <artifactId>jstl-impl</artifactId>
        <version>1.2</version>
    </dependency>
    <!-- spring相关jar -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- spring相关jar 结束 -->
    <!-- mysql 数据库 jar -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.49</version>
    </dependency>
    <!-- mysql 数据库 end -->
    <!-- mybatis 开始  -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.7</version>
    </dependency>
    <!-- mybatis  结束 -->
    <!-- mybatis 和 spring的整合包 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.4</version>
    </dependency>
    <!-- mybatis 和 spring的整合包  end -->
    <!-- 日志 开始 -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.13.3</version>
    </dependency>
    <!-- 日志 结束 -->
    <!--pagehelper分页-->
     <dependency>

            <groupId>com.github.pagehelper</groupId>

            <artifactId>pagehelper</artifactId>

            <version>5.2.0</version>

        </dependency>
    <!-- 分页插件 结束 -->
    <!-- lombok 开始 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>
    <!-- lombok 结束 -->
</dependencies>

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>



    </project>

2.5.2 定义相关类

2.5.2.1 domain

package com.bjpowernode.domain;

import lombok.Data;
/**
 * @Description: 用户类
 */
@Data
public class User {

    private Integer id;
    private String username;
    private String password;
    private String realname;
}

2.5.2.2 mapper

package com.bjpowernode.mapper;

import com.bjpowernode.domain.User;

import java.util.List;

/**
 * @Description: 用户数据操作类
 */
public interface UserMapper {
    /**
     * 查询所有 用户信息
     * @return
     */
    List<User> selectAll();
}

2.5.2.3 service

package com.bjpowernode.service;

import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;

public interface IUserService {
    /**
     *  分页查询数据
     * @param page
     * @param limit
     * @return
     */
    PageInfo<User> queryPage(Integer page,Integer limit);
}



package com.bjpowernode.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;
import com.bjpowernode.mapper.UserMapper;
import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Description: 用户业务实现类
 */
@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserMapper userMapper;
    /**
     * 分页查询数据
     * @param page
     * @param limit
     * @return
     */
    @Override
    public PageInfo<User> queryPage(Integer page, Integer limit) {
        Page<User> pageObj = PageHelper.startPage(page, limit);
        userMapper.selectAll();
        return pageObj.toPageInfo();
    }
}

2.5.2.4 controller

package com.bjpowernode.controller;

import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;
import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

/**
 * @Description: 用户控制类
 */
@Controller
@RequestMapping("user")
public class UserController {
    @Autowired
    private IUserService  userService;

    @RequestMapping("page.do")
    public ModelAndView page(@RequestParam(name = "page",required = false,defaultValue = "1") Integer page, @RequestParam(name = "limit",required = false,defaultValue = "10")  Integer limit){
        PageInfo<User> pageInfo = userService.queryPage(page, limit);
        ModelAndView modelAndView = new ModelAndView();
        //设置视图路径
        modelAndView.setViewName("/list.html");
        //设置数据
        modelAndView.addObject("pageInfo",pageInfo);
        return  modelAndView;
    }
}

2.5.2.5 页面

<html>
<head>
    <title>Title</title>
</head>
<body>
    <table >
        <thead>
            <th>ID</th>
            <th>username</th>
            <th>password</th>
            <th>realname</th>
        </thead>
    </table>
</body>
</html>

2.5.3 配置文件
2.5.3.1 数据库配置文件
#数据库连接信息
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/stmng?useUnicode=true&characterEncoding=utf8&useSSL=false
jdbc.username=root
jdbc.password=root
2.5.3.2 日志配置文件

# 全局日志配置
log4j.rootLogger=DEBUG, stdout
# MyBatis 日志配置
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

2.5.3.3 spring核心配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!-- 整合mybatis -->
    <!--1. 引入数据库配置文件  因为创建数据源  -->
    <context:property-placeholder location="classpath:jdbc.properties" system-properties-mode="FALLBACK" />
    <!--2. 创建数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    <!--3. 创建SqlSessionFactoryBean -->
    <!-- configuration 指 mybatis的核心配制信息 -->
    <bean id="configuration" class="org.apache.ibatis.session.Configuration">
        <property name="logImpl" value="org.apache.ibatis.logging.log4j.Log4jImpl"/>
        <property name="cacheEnabled" value="true" />
    </bean>
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 使用 configuration 取代了  mybatis的核心配置文件-->
        <property name="configuration" ref="configuration"/>
        <!-- 配置mapper 映射 文件-->
        <property name="mapperLocations" value="classpath:mapper/**Mapper.xml" />
        <!-- 配置类别名 -->
        <property name="typeAliasesPackage" value="com.bjpowernode.domain" />
        <!-- 配制插件 -->
        <property name="plugins">
            <array>
                <!-- 分页插件 -->
                <bean class="com.github.pagehelper.PageInterceptor" />
            </array>
        </property>
    </bean>
    <!--4. Mapper接口的扫描 自动创建代理类 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 被扫描的mapper接口  产生接口的实现类 对象 使用SqlSession.getMapper(接口.class) -->
        <property name="basePackage" value="com.bjpowernode.mapper" />
        <!-- 注入一个SqlSessionFactoryBean  为了产生 SqlSession -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean" />
    </bean>
    <!-- 5. 配置事务 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 指定被管理事务的数据源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 配置声明式事务  XML  注解 -->
    <!-- 开启事务注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"  />

    <!-- 开启组件扫描 创建 对象 -->
    <context:component-scan base-package="com.bjpowernode" />
</beans>

2.5.3.4 springmvc配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 开启组件扫描 -->
    <!-- 扫描的目的是为了将 处理器放入到HandlerMapping中 -->
    <context:component-scan base-package="com.bjpowernode.controller" />
    <!-- 开启springmvc注解 -->
    <mvc:annotation-driven />
</beans>

2.5.3.5 Mapper配置文件

<?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.bjpowernode.mapper.UserMapper">
    <select id="selectAll" resultType="User">
        select  * from user
    </select>
</mapper>

2.5.3.6 web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!-- 配置监听器需要加载的配置文件 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-context.xml</param-value>
  </context-param>
  <!-- 加载初始化spring核心配置文件
      配置监听器  启动时就加载 spring核心配置文件 IOC容器相关初始化
   -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!-- 配置 springmvc -->
  <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.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

2.6 SpringMVC获取Servlet作用域

package com.bjpowernode.util;

import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

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

/**
 * @Description: 获取Servlet 作用域对象工具类
 *      HttpServletRequest
 *      HttpSession
 *      ServletContext
 */
public class WebScopeUtil {

    /**
     *  获取当前  HttpServletRequest 对象
     * @return
     */
    public static HttpServletRequest getRequest(){
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        return  requestAttributes.getRequest();
    }

    /**
     * 获取当前请求绑定的session
     * @return
     */
    public static HttpSession getSession(){
        return  getRequest().getSession();
    }

    /**
     *  获取全局容器对象
     * @return
     */
    public static ServletContext getContext(){
        //getRequest().getServletContext(); // ServletContext 的生命周期 是早于 HttpServletRequest
        //所以不能通过 HttpServletRequest 获取ServletContext  可能发生 NullpointException
        return  ContextLoader.getCurrentWebApplicationContext().getServletContext();
    }
}

2.7 SpringMVC内置的编码过滤器

在springmvc中,为了解决乱码问题,springmvc提供了内置的编码过滤器。在使用时,只需要在web.xml中进行配置即可。

<!-- 编码过滤器 -->
<filter>
  <filter-name>charsetFilter</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>charsetFilter</filter-name>

<!-- 只对springmvc处理的请求进行编码过滤 -->
  <servlet-name>springmvc</servlet-name>
</filter-mapping>

2.8 SpringMVC返回JSON

{key1:value1,key2:value2}:key为String,value为Object
[{},{},{}…]

实体类对象、Map<String,Object>、List<实体类>、List<Map<String,Object>>

fastjson.jar: JSON.toJSONString(Object)

在springmvc中,默认返回的数据不论是什么格式,都当做视图进行解析。会根据返回值的toString的结果,当做路径去查找视图的模板,如果想要返回JSON,则需要使用注解,标识该方法返回的是JSON数据,不要当做视图路径进行路径的查找.该注解为:@ResponseBody.因为springmvc有内置的消息转换器,如果想要特殊设置,需要进行XML配置.

2.8.1 XML配置的形式
XML配置形式,是修改了默认结果处理,全局生效的。使用注解@ResponseBody,标识该方法返回的内容不是URL地址,而是一个消息,使用输出对象输出给客户端。

@RequestMapping

name : 方法映射名称

value/path : 方法访问路径

method : 支持的请求的方法类型:

GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE

params : 请求必须有的参数

headers : 请求必须有的头信息

consumes : 指定请求的数据格式类型 : 普通文本、表单格式、JSON

produces : 指定返回数据的格式类型 :JSON 、HTML

<!-- 配置JSON转换器 -->
<!--<bean id="config" class="com.alibaba.fastjson.support.config.FastJsonConfig">-->
<!--</bean>-->
<mvc:annotation-driven  >
    <mvc:message-converters register-defaults="true">
        <!--
            将内容转化为字符串消息  使用 IO发送给客户端
            此时只支持字符串
        -->
        <!--<bean class="org.springframework.http.converter.StringHttpMessageConverter" />-->
        <!-- 将内容转化为JSON字符串 发送客户端  能够处理对象-->
        <!-- date  年--日 时:分:秒 -->
        <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter" />
    </mvc:message-converters>
</mvc:annotation-driven>

2.8.2 注解
SpringMVC中,有内置的转换器,但是SpringMVC内置的转换器需要相关jar包,需要jackson的jar包。只需要导入jar包后,使用@ResponseBody标识返回的数据是消息即可。SpringMVC自动将返回数据当做JSON字符串处理,并且消息按照UTF-8进行编码。如果@ResponseBody放在类上,类中所有的方法都返回的是消息,不是视图资源。

注意:

@RestController

是 @ResponseBody, @Controller 结合,标识该类是一个处理器,并且处理器中所有的方法都返回的是消息。

<!-- 导入jackson的jar包 -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.11.2</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.11.2</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.11.2</version>
</dependency>

2.9 文件上传下载

在springmvc中,也对文件上传进行了封装。更进一步的简化的文件上传,只需导入文件上传相关的jar包和处理文件上传的解析器即可。

2.9.1 文件上传
2.9.1.1 导入jar包

<!-- 文件上传相关依赖jar  -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

2.9.1.2 配置文件上传的解析器

在SpringMVC的核心配置文件中,新增文件上传解析器配置:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

    <!--文件格式编码-->

    <property name="defaultEncoding" value="UTF-8"></property>

    <!--配置单个文件上传大小:1M-->

    <property name="maxUploadSizePerFile" value="1048576"></property>

    <!--配置所有文件上传总大小:10M-->

    <property name="maxUploadSize" value="10485760"></property>

</bean>

2.9.1.3 处理文件上传请求

页面

<html>
<head>
    <title>文件上传</title>
</head>
<body>
<form action="file/upload2.do" method="post" enctype="multipart/form-data">
    <p>
       普通的文本数据:<input  name="name" type="text" />
    </p>
    <p>
        文件数据:<input  name="userImg" type="file" />
    </p>
    <p>
        文件数据:<input  name="userImg" type="file" />
    </p>
    <input type="submit" value="提交">
</form>
</body>
</html>

处理器

package com.bjpowernode.controller;
import cn.hutool.core.img.Img;
import cn.hutool.core.img.ImgUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

@Controller
@RequestMapping("file")
public class FileUploadController {

    /**
     *  如果是单个文件,则直接使用MultipartFile 对象进行接收
     *  普通的文本数据 则直接使用相应的类型进行接收
     *  如果名字不一致 @RequestParam 注解 处理名称
     * @param name
     * @param file
     * @return
     */
    @RequestMapping("upload1.do")
    public String upload1(String name,@RequestParam("userImg") MultipartFile file){
        System.out.println("文本数据为:"+name);
        System.out.println("文件数据为:"+file.getName());//input name 属性值
        System.out.println("文件数据为:"+file.getSize()); // 文件的字节大小
        System.out.println("文件数据为:"+file.getOriginalFilename()); //文件的真实名称
        return "/success.html";
    }

    /**
     *  如果是多个文件 则使用MultipartFile[] 数组进行接收
     * @param name
     * @param files
     * @return
     */
    @RequestMapping("upload2.do")
    public String upload2(String name,@RequestParam("userImg") MultipartFile[] files){
        System.out.println("文本数据为:"+name);
        for (MultipartFile file : files) {
            System.out.println("文件数据为:"+file.getName());//input name 属性值
            System.out.println("文件数据为:"+file.getSize()); // 文件的字节大小
            System.out.println("文件数据为:"+file.getOriginalFilename()); //文件的真实名称
            //将文件进行保存
            File newFile = new File("d://"+file.getOriginalFilename());
            try {
                Font font = new Font("微软雅黑",Font.BOLD,15);
                ImgUtil.pressText(file.getInputStream(),new FileOutputStream(newFile),"我是水印", Color.RED,font,1,1,0.5f);
                //将文件保存在磁盘上
                //file.transferTo(newFile);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "/success.html";
    }
}

/**
 * 一个file控件同时上传多个
 * MultipartFile代表一个文件  MultipartRequest:封装了多个MultipartFile对象
 */
@RequestMapping("/uploadMany2.do")
public void uploadMany2(MultipartRequest mr) throws IOException {
    List<MultipartFile> fileList = mr.getFiles("f");
    for (int i = 0;fileList!=null && i < fileList.size(); i++) {
        MultipartFile tempFile = fileList.get(i);
        //将上传的文件保存到D:\\uploads\\
        String name = tempFile.getOriginalFilename();//获取上传文件的名字 1.2.3.jpg 1.jpg  1.avi  C:\\users\\desktop\\1.jpg
        //获取上传文件的拓展名
        int index = name.lastIndexOf(".");
        String ext = name.substring(index);//.jpg .avi  .pptx
        //将上传的文件保存到指定目录
        String fileName = UUID.randomUUID().toString();
        File file = new File("D:\\uploads\\"+fileName+ext);
        tempFile.transferTo(file);
    }
}

2.9.2 文件下载

2.9.2.1 方案一(推荐):
文件下载的本质,就是获取服务器的文件数据信息,使用字节流将数据传递给客户端。

  1. 使用输入流,将磁盘文件读到内存中。

  2. 使用网络输出流,将数据输出给客户端。

package com.bjpowernode.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URLEncoder;

/**
 * @Description: 文件下载示例
 */
@Controller
@RequestMapping("download")
public class DownLoadController {

    /**
     * 文件下载的方法
     */
    @RequestMapping("download.do")
    public  void download(HttpServletResponse response) throws Exception {
        File file = new File("E:\\猪图片.jpg");//本地磁盘文件
        //使用输入流  将文件读入内存中
        FileInputStream fis = new FileInputStream(file); // 找参照物   将程序运行的内存当做参照物
        byte[] b = new byte[1024];
        int len = -1;
        ServletOutputStream out = response.getOutputStream();//输出流  输出客户端
        //浏览器 默认打开了这个文件
        //设置响应类型 通知浏览器 不要打开
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        //文件的名称  不对
        //设置响应的文件的名称
        //如果响应的数据的名称是中文,在设置文件的名称时 要先将文件的名称进行编码 再进行传输
        String name = URLEncoder.encode("猪图片.jpg", "UTF-8");
        System.out.println("编码后的名字:"+name);
        response.setHeader("Content-Disposition", "attachment; filename="+name);
        //循环读  循环写
        while((len = fis.read(b)) != -1) {
            out.write(b,0,len);
            out.flush();
        }
        out.close();
        fis.close();
    }
}

2.9.2.2 方案二:

springMVC中为了简化文件的下载,封装了实体类:ResponseEntity,可以将文件数据封装在ResponseEntity中。

package com.bjpowernode.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URLEncoder;

/**
 * @Description: 文件下载示例
 */
@Controller
@RequestMapping("/download")
public class DownLoadController {

    @RequestMapping("/download2.do")
    public ResponseEntity<Byte[]> download() throws Exception {
        File file = new File("E:\\猪图片.jpg");//本地磁盘文件
        //使用输入流  将文件读入内存中
        FileInputStream fis = new FileInputStream(file); // 找参照物   将程序运行的内存当做参照物
        //文件的大小
        long length = file.length();
        //创建一个和文件一样大小的字节数组  一次性将数据读入到内存中  如果文件量过大,请求比较频繁 存在 崩溃的风险
        byte[] fileByte = new byte[(int) length];//一个G 的   byte 数组  64 G    65个人下载   1分钟
        //一次性将文件数据读入到数组中
        fis.read(fileByte);
        // springmvc 中封装的 响应实体 :
        //设置响应码
        //设置响应的数据头信息
        //设置响应数据
        HttpHeaders headers = new HttpHeaders(); //响应头信息
        //设置响应的数据为流数据  告诉浏览器 不要解析
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        //设置下载的文件的名称  中文字符串要进行编码
        headers.setContentDispositionFormData("filename","猪图片.jpg");
        ResponseEntity responseEntity = new ResponseEntity(fileByte,headers, HttpStatus.OK);
        return responseEntity;
    }
}

2.10 SpringMVC中的拦截器

SpringMVC提供HandlerInteceptor接口,这个接口用于拦截处理具体的Handler中的方法,在具体的Handler中的方法执行前后及返回视图之间都可以进行相关扩展操作。

2.10.1 如何使用拦截器
2.10.1.1 创建类实现HandlerInteceptor接口

package com.bjpowernode.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

/**
 * @Description: 自定义拦截器
 */
public class MyInterceptor implements HandlerInterceptor {
    /**
     * 在执行具体的Handler中的方法前执行
     * @param request  当前的请求对象
     * @param response  当前的响应对象
     * @param handler   具体的处理器中将要执行的方法
     * @return   boolean  如果 返回 true 则执行Handler中的方法   false 则 不执行handler中的方法
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("我是拦截器中preHandle 方法");
        return true;
    }
    /**
     *  在具体的Handler中的方法执行完成 但是没有做具体的视图解析操作
     * @param request  当前 请求对象
     * @param response  当前响应对象
     * @param handler 具体的处理器中将要执行的方法
     * @param modelAndView 具体的处理器中将要执行的方法 返回的结果
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("我是拦截器中postHandle 方法");
        //在具体的解析之前  修改视图模型中数据
        modelAndView.addObject("name","韩梅梅");
    }
    /**
     *  完成了视图解析后 整个方法执行完成调用的方法 在finally中调用 或者出现异常也会调用
     * @param request   当前请求对象
     * @param response  当前响应对象
     * @param handler   具体的处理器中将要执行的方法
     * @param ex         具体的处理器中抛出的异常
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("我是拦截器中afterCompletion 方法");
        System.out.println(ex.getMessage());
        request.setAttribute("msg","网管去火星了!");
        request.getRequestDispatcher("/500.html").forward(request,response);
    }
}
 

2.10.1.2 配置拦截器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context 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:component-scan base-package="com.bjpowernode.controller" />
    <!-- 开启 mvc注解 -->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!-- 文件上传的解析器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" >
        <!--<property name="maxUploadSize" value="1"></property>-->
    </bean>
    <!-- 配置springmvc的拦截器 -->
    <mvc:interceptors>

        <mvc:interceptor>
            <!-- 拦截器的资源路径  /** 拦截所有  ** 表示多层目录 -->
            <mvc:mapping path="/**"/>
            <!-- 不拦截的资源路径 -->
            <mvc:exclude-mapping path="/user/page.do"/>
            <!-- 自定义的拦截器 -->
            <bean id="myInterceptor" class="com.bjpowernode.interceptor.MyInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>
</beans>

注意:

  1. 在拦截器中,最先执行preHandle,然后执行Handler中具体的方法,再然后执行postHandle和afterCompletion。preHandle就是前置的拦截的方法,返回如果为true,则执行处理器中的方法,如果为false则不执行处理器中的方法。postHandle是在Handler中具体的方法执行完成,但是没有交给视图解析器之前执行,afterCompletion在视图解析器完成了视图解析之后执行的。

  2. 拦截器是拦截器的方法,被DispatcherServlet代理调用的方法,如果请求的不是Handler,拦截器是不会拦截的。index.html由于是由tomcat默认的servlet进行返回的,不会执行DispatcherServlet中的doDispatch,那么拦截器无法进行拦截。

2.10.2 Interceptor和Filter的区别
Filter是Java Web的规范,拦截的是请求,任何JavaWeb项目都可以有Filter,但是Interceptor是SpringMVC提供的一套规范HandlerInterceptor,只适用SpringMVC自身,并且只能对DispatherServlet处理器的请求生效,拦截的方法。从范围上说,任何JavaWeb项目都有Filter,但是未必有Interceptor。

1、filter可以应用于任何的javaweb项目;inteceptor应用于springmvc框架

2、Filter可以过滤所有请求资源(不限于html、css、js、images等);Interceptor只能拦截所有的controller方法

3、Filter过滤路径时,没有排除选项;Interceptor可以排除拦截路径

2.11 异常处理器

在spring中,相对完善的异常处理器机制,spring可以自己定义处理异常的规则,这种处理异常规则的程序,就被称之为异常处理器。其实,异常处理器就是对controller的增强,因为异常是向上抛,controller调用service,service调用mapper,controller属于最上层,所以最终异常都会汇集到controller。因此,spring提供了@ControllerAdvice注解,表示对controller增强类。并且还提供了@ExceptionHandler这个注解,当发生异常时,该注解修饰的方法就会执行。

在实际开发中,异常主要分为两类:

  1. 系统异常,JDK中定义的异常

  2. 业务异常,开发者自己定义的异常

一般是将系统异常转化为业务异常,开发者只处理业务异常。使用try…catch…将代码包裹起来,在catch中抛出自定义的异常,这种方案就是将系统异常转化为业务异常。因为很多数据操作,事务需要异常进行数据回滚。

package com.bjpowernode.handler;

import com.bjpowernode.exception.BussiException;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

/**
 * @Description: 全局异常处理器
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    /**
     *  具体的异常处理方法
     * @param exception
     */
    @ExceptionHandler
    public void doException(Exception exception){
        //exception  FileNotFound indexOutof  xxxx
        //判断 异常类型是不是自定义异常
        if (exception instanceof BussiException){
            BussiException ex = (BussiException) exception;
            Integer code = ex.getCode();//获取异常码
            String msg = ex.getMsg();//获取异常消息
            System.out.println(code +":"+msg);
            //Result  转化为JSON字符串   将JSON字符串返回给客户端
        }
    }
}

package com.bjpowernode.exception;

/**
 * @Description: 自定义异常
 */
public class BussiException extends RuntimeException {
    private Integer code;//异常码
    private String msg;//异常消息
    public BussiException(){}

    public BussiException(Integer code,String msg){
        super(msg);
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}



package com.bjpowernode.controller;

import com.bjpowernode.exception.BussiException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/test")
public class TestController {

    @RequestMapping("/test.do")
    public String test(){
        //数据校验  可能发生的情况  很多种
        int m = 0;
        try {
            System.out.println(100/m);
        }catch (Exception e){
            e.printStackTrace();//打印异常
            //自己抛出了异常
            throw  new BussiException(1001,"被除数不能为0");
        }

        return  "/success.html";
    }
}
 

2.12 springmvc中数据校验

springmvc中的数据校验时通过hibernate-validator实现,对实体类中的字符串有效。

1、引入hibernate-validator依赖

2、在实体类中的字符串(正则表达式)属性上添加相关注解

3、可以用hibernate-validor提供的特有注解对Long、Integer、Float做校验

4、在被校验的实体类前添加@Valid注解

5、当实体类中的数据格式发生错误时,错误信息被封装到了BindResult对象中去,BindResult必须和实体类紧紧挨在一起

2.13 Restful风格

Restful风格适合参数少、参数不敏感的请求地址。使用了restful风格的请求地址,就不能使用.do的方式请求

Resustful风格:

  1. 请求地址问题

  2. 请求方式问题

http://localhost:8080/getBooksByFenye.do?pageNum=1&pageSize=5

http://localhost:8080/getBooksByFenye/1/5

2.13.1 Http协议设计的初衷
HTTP协议在设计时,期望使用一个URL表示一个资源。然后,根据不同的动作:GET、POST、PUT、DELETE等等表示对一个资源的各种操作。

如:

获取这个资源就使用GET, @GetMapping(“/”)

修改这个资源PUT, @PutMapping()

删除这个资源用DELETE,@DeleteMapping()

创建这个资源使用POST。 @PostMapping()

但是在实际使用中,多个URL表示一个资源,例如:新增用户: addUser.do,修改用户:updateUser.do,删除用户:deleteUser.do,查询一个用户:getUser.do。这时候,出现一个资源存在多个URL。在一定程度声,违背了HTTP协议的设计初衷,并且命名也是个问题。

2.13.2 Restful设计思想

  1. 使用一个URL表示一种资源

  2. 客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源

  3. 通过操作资源的表现形式来操作资源

2.13.3 在SpringMVC中使用Restful
SpringMVC也支持Restful风格,但是目前存在一些问题。主要不是很好支持PUT请求,没有办法获取到PUT请求的数据。

2.13.3.1 将DispatherServlet的映射地址改为
由于将DispatherServlet的映射路径,改为了/,则所有的请求都由DispatherServlet处理,静态的资源文件不在处理器映射器中,会出现404。并拦截器拦截DispatherServlet中调用Handler中的方法,改为/,则所有的请求都会被拦截。

则需要在SpringMVC的核心配置文件中,新增启用默认的Servlet的处理器。

<!-- 启用默认Servlet -->
<mvc:default-servlet-handler/>

并且注意,配置拦截器时,将静态资源不进行拦截,要排除:

<mvc:exclude-mapping path="/resouces/**"/>

2.13.3.2 配置处理PUT请求的拦截器

<!-- 处理put请求的拦截器 -->
<filter>
  <filter-name>restful</filter-name>
  <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>restful</filter-name>
  <servlet-name>springmvc</servlet-name>
</filter-mapping>

2.13.3.3 处理器代码

package com.bjpowernode.controller;

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

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("user")
public class UserController {

//    @RequestMapping(method = RequestMethod.GET)
//    //@GetMapping
//    public Object get(Integer id){
//        System.out.println("get请求");
//        Map<String,Object> data = new HashMap<>();
//        data.put("code",200);
//        data.put("msg","get请求");
//        return  data;
//    }
    @GetMapping("{id}/{name}") //后台的获取方式 使用 {} 进行包裹  并且 在方法参数中 使用@PathVariable
    // 这种将参数拼接在URL上的方式 只支持 GET 请求和 DELETE请求
    public Object get1(@PathVariable("id") Integer id,@PathVariable("name") String name){
        System.out.println("get请求");
        System.out.println(id);
        System.out.println(name);
        Map<String,Object> data = new HashMap<>();
        data.put("code",200);
        data.put("msg","get请求");
        return  data;
    }
    //@RequestMapping(method = RequestMethod.PUT)
    @PutMapping
    public Object put(Integer id){
        System.out.println("PUT请求");
        Map<String,Object> data = new HashMap<>();
        data.put("code",200);
        data.put("msg","PUT请求");
        return  data;
    }

    @RequestMapping(method = RequestMethod.POST)
    @PostMapping
    public Object post(Integer id){
        System.out.println("post请求");
        Map<String,Object> data = new HashMap<>();
        data.put("code",200);
        data.put("msg","post请求");
        return  data;
    }

    //@RequestMapping(method = RequestMethod.DELETE)
    @DeleteMapping
    public Object delete(Integer id){
        System.out.println("delete请求");
        Map<String,Object> data = new HashMap<>();
        data.put("code",200);
        data.put("msg","delete请求");
        return  data;
    }
}

2.13.3.4 页面代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <button id="btn1">get</button>
    <button id="btn2">put</button>
    <button id="btn3">delete</button>
    <button id="btn4">post</button>
    <button id="btn5">get-1111</button>
    <script src="resources/jquery.js"></script>
    <script>
        $("#btn1").click(function () {
            $.get("user",{id:1001},function (rs) {
                console.log(rs);
            })
        });
        $("#btn2").click(function () {
           $.ajax({
               url:"user",
               type:"PUT",
               data:{id:1001},
               success:function (rs) {
                   console.log(rs);
               }
           })
        });
        $("#btn3").click(function () {
            $.ajax({
                url:"user",
                type:"DELETE",
                data:{id:1001},
                success:function (rs) {
                    console.log(rs);
                }
            })
        });
        $("#btn4").click(function () {
            $.post("user",{id:1001},function (rs) {
                console.log(rs);
            })
        });
        $("#btn5").click(function () {
            //将参数 拼接在URL上面
            $.get("user/11111/lucy",function (rs) {
                console.log(rs);
            })
        });
    </script>
</body>
</html> 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1243087.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

「Verilog学习笔记」 输入序列不连续的序列检测

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 题目要求检测a的序列&#xff0c;a为单bit输入&#xff0c;每个时刻可能具有不同的值&#xff0c;且并不是每一个数据都是有效的&#xff0c;需要根据data_valid信号进行判…

【knife4j-spring-boot】Springboot + knife4j-spring-boot 整合swagger脚手架

swagger-boostrap-ui从1.x版本到如今2.x&#xff0c;同时也更改名字Knife4j 在此记录下 knife4j-spring-boot-starter 的整合。 只需要引入knife4j-spring-boot-starter&#xff0c;无需引入其他的swagger包&#xff0c;knife4j-spring-boot-starter已经包含。 官方版本说明…

软件系统测试有哪些测试流程?系统测试报告编写注意事项

在软件开发的过程中&#xff0c;系统测试是至关重要的一环&#xff0c;它的目的是验证和评估软件产品是否符合预期的质量标准&#xff0c;以确保系统的稳定性、可靠性和安全性。 一、软件系统测试的测试流程 1、需求分析与测试计划制定&#xff1a;根据需求分析确定测试目标、…

C++ 问题 怎么在C++11标准语法中调用C++20的类

一. 问题 在工作中,因为一个算法功能需要跟别的部门对接,他们提供了该算法的头文件.h,静态库.lib,动态库.dll。但是头文件中使用了C++20才有的新特性,如#include等,而本地使用的vs2015开发环境,只支持C++11标准语法,这种情况下,该怎么把该算法集成到本地项目中呢? …

前端已死?看看我的秋招上岸历程

背景 求职方向&#xff1a;web前端 技术栈&#xff1a;vue2、springboot&#xff08;学校开过课&#xff0c;简单的学习过&#xff09; 实习经历&#xff1a;两段&#xff0c;但都是实训类的&#xff0c;说白了就是类似培训&#xff0c;每次面试官问起时我也会坦诚交代&…

激光切割设备中模组的作用有哪些?

激光切割设备是一种高精度的自动化加工设备&#xff0c;用于对金属、非金属等材料进行精确切割。直线模组作为激光切割设备的重要组成部分&#xff0c;在激光切割设备中起着重要的作用&#xff0c;为设备的运动系统提供了高精度、高稳定性和高效率的运动控制。 1、高精度的位置…

【C++初阶】第一站:C++入门基础(中)

前言&#xff1a; 这篇文章是c入门基础的第一站的中篇,涉及的知识点 函数重载:函数重载的原理--名字修饰 引用:概念、特性、使用场景、常引用、传值、传引用效率比较的知识点 目录 5. 函数重载 &#xff08;续&#xff09; C支持函数重载的原理--名字修饰(name Mangling) 为什么…

【C语言】qsort函数

目录 简介 头文件 ​编辑 函数原型&#xff1a; 参数函数如何写&#xff1a; 参数函数要求&#xff1a; qsort对整性数据的排序&#xff1a; qsort对字符型数据的排序&#xff1a; 对结构体类型的内部元素排序&#xff1a; 函数的底层是以快速排序实现的 但是本文不深入…

关于「光学神经网络」的一切:理论、应用与发展

/目录/ 一、线性运算的光学实现 1.1. 光学矩阵乘法器 1.2. 光的衍射实现线性运行 1.3. 基于Rayleigh-Sommerfeld方程的实现方法 1.4. 基于傅立叶变换的实现 1.5. 通过光干涉实现线性操作 1.6. 光的散射实现线性运行 1.7. 波分复用&#xff08;WDM&#xff09;实现线性运…

phpstudy和IDEA 配置php debug

1.安装xdebug 扩展&#xff0c;phpinfo() 查看 2.配置php.ini zend_extensionD:/phpstudy_pro/Extensions/php/php7.4.3nts/ext/php_xdebug.dll xdebug.collect_params1 xdebug.collect_return1 xdebug.auto_traceOn xdebug.trace_output_dirD:/phpstudy_pro/Extensions/php_l…

vue + docxtemplater 导出 word 文档

一、痛点 word 导出 这种功能其实之前都是后端实现的&#xff0c;但最近有个项目没得后端。所以研究下前端导出。 ps&#xff1a; 前端还可以导出 pdf&#xff0c;但是其分页问题需要话精力去计算才可能实现&#xff0c;并且都不是很完善。可参考之前的文章&#xff1a;利用 h…

Flink 替换 Logstash 解决日志收集丢失问题

在某客户日志数据迁移到火山引擎使用 ELK 生态的案例中&#xff0c;由于客户反馈之前 Logstash 经常发生数据丢失和收集性能较差的使用痛点&#xff0c;我们尝试使用 Flink 替代了传统的 Logstash 来作为日志数据解析、转换以及写入 ElasticSearch 的组件&#xff0c;得到了该客…

PasteNow for mac剪贴板工具

PasteNow 是一款简单易用的剪贴板管理工具&#xff0c;可帮助用户快速存储和管理剪贴板上的文本和图片内容。用户可以使用 PasteNow 软件快速将文本内容保存到不同的笔记或页面中&#xff0c;也可以方便地将剪贴板上的图片保存到本地或分享给其他应用程序。 此外&#xff0c;P…

Java互联网+医院智能导诊系统源码 自动兼容H5小程序、Uniapp

随着信息和通信技术的进步,智能和移动技术越来越普遍,尤其在医疗保健领域,一些新型卫生信息系统被不断开发出来支持医院和其他卫生保健组织的管理和运作。 智能导诊系统是嵌入到医院和医疗保健卫生中心 HIS系统中的一种专门导诊系统,通过智能语音交互的方式帮助用户完成导诊、分…

XC2303 PFM 升压 DC-DC 变换器 SOT23-3封装 体积小 外围简单 适合小电流产品

XC2303系列产品是一种高效率、低纹波、工作频率高的 PFM 升压 DC-DC 变换器。XC2303系列产品仅需要四个元器,就可完成将低输入的电池电压变换升压到所需的工作电压&#xff0c;非常适合于便携式1~4 节普通电池应用的场合。 电路采用了高性能、低功耗的参考电压电路结构&#xf…

深度学习常见激活函数:ReLU,sigmoid,Tanh,softmax,Leaky ReLU,PReLU,ELU整理集合,应用场景选择

文章目录 1、ReLU 函数&#xff08;隐藏层中是一个常用的默认选择&#xff09;1.1 优点1.2 缺点 2、sigmoid 函数2.1 优点2.2 缺点 3、Tanh 函数3.1 优点3.2 缺点 4、softmax 函数&#xff08;多分类任务最后一层都会使用&#xff09;5、Leaky ReLU 函数5.1 优点5.2 缺点 6、PR…

【JavaEE初阶】 JavaScript相应的WebAPI

文章目录 &#x1f332;WebAPI 背景知识&#x1f6a9;什么是 WebAPI&#x1f6a9;什么是 API &#x1f38d;DOM 基本概念&#x1f6a9;什么是 DOM&#x1f6a9;DOM 树 &#x1f340;获取元素&#x1f6a9;querySelector&#x1f6a9;querySelectorAll &#x1f384;事件初识&am…

WordPress用sql命令批量删除所有文章

有时我们需要将一个网站搬迁到另一个服务器。我们只想保留网站的模板样式&#xff0c;而不需要文章内容。一般情况下我们可以在后台删除已发表的文章&#xff0c;但如果有很多文章&#xff0c;我们则需要一次删除所有文章。 WordPress如何批量删除所有文章 进入网站空间后台&a…

chrome F12 performance 性能分析

本文主要是介绍chrome F12 performance 性能分析&#xff0c;对大家解决编程问题具有一定的参考价值&#xff0c;需要的程序猿们随着小编来一起学习吧&#xff01; 页面加载速度慢&#xff0c;到底是多少秒&#xff0c;瓶颈在哪里&#xff1f; 前端性能工具Chrome performance…

学生心目中的好老师

在教育的世界里&#xff0c;一个好老师可以改变一个学生的人生轨迹。他们不仅传授知识&#xff0c;更是引导学生发现自己的潜力&#xff0c;激发他们对未来的憧憬。那么&#xff0c;如何成为一名学生心目中的好老师呢&#xff1f; 拥有一颗热爱教育的心。深深的热爱着教育事业&…