Java零基础——SpringMVC篇

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> 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL-进阶

存储引擎 MySQL体系结构 连接层&#xff1a; 最上层是一些客户端和连接服务&#xff0c;主要完成一些类似于连接处理、授权认证、及相关的安全方案。服务器也会为安全接入的每个客户端验证它所具有的操作权限。服务层&#xff1a; 第二层架构主要完成大多数的核心服务功能&…

基于若依的ruoyi-nbcio流程管理系统修改代码生成的sql菜单id修改成递增id(谨慎修改,大并发分布式有弊端)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 1、我看我的原先系统生成的代码id都是很长如下&#xff1a; -- 菜单 SQL insert into sys_menu (menu_id…

佳易王个体诊所管理系统电子处方软件,诊所系统软件有哪些,佳易王门诊病历电子处方 软件教程

佳易王个体诊所管理系统电子处方软件&#xff0c;诊所系统软件有哪些&#xff0c;佳易王门诊病历电子处方 软件教程 上图&#xff0c;软件不仅可以打印电子处方&#xff0c;而且可以记录病历和病历查询。 上图&#xff0c;软件支持中医和西医处方打印&#xff0c;上图为西医打印…

TrustAsia亮相Matter开发者大会,荣获Matter优秀赋能者奖

11月22日&#xff0c;由CSA&#xff08;连接标准联盟&#xff09;中国成员组主办&#xff0c;CSHIA承办的“Matter中国区开发者大会2023” 于杭州举行。 会上&#xff0c;连接标准联盟中国成员组主席宿为民博士、连接标准联盟亚洲区架构师杨莉女士、CSHIA秘书长|中智盟投资创始…

HarmonyOS 设备管理开发:USB 服务开发指导

基本概念 USB 服务是应用访问底层的一种设备抽象概念。开发者根据提供的 USB API&#xff0c;可以获取设备列表、控制设备访问权限、以及与连接的设备进行数据传输、控制命令传输等。 运作机制 USB 服务系统包含 USB API、USB Service、USB HAL。 图 1 USB 服务运作机制 ●…

CAD随机多面体_圆柱试件3D插件

插件介绍 CAD随机多面体_圆柱试件3D插件可用于在AutoCAD软件内生成随机三维多面体及外侧圆柱体试件。插件可确保多面体之间不发生干涉&#xff0c;且多面体与外侧圆柱体试件之间保持适配关系&#xff0c;确保生成的模型导入有限元软件后几何合理有效。本插件主要可应用于三维混…

基于51单片机倾角MPU6050老人跌倒远程GSM短信报警器+源程序

一、系统方案 1、本设计采用这51单片机作为主控器。 2、MPU6050角度值送到液晶1602显示。 3、红外传感器检测心率。 4、跌倒远程GSM报警。 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先是系统初始化 void LCD_Init() //初始化液晶时间显示 { write_com…

快速成为接口测试高手:实用指南!

大量线上BUG表明&#xff0c;对接口进行测试可以有效提升产品质量&#xff0c;暴露手工测试时难以发现的问题&#xff0c;同时也能缩短测试周期&#xff0c;提升测试效率。但在实际执行过程中&#xff0c;接口测试被很多同学打上了“上手难&#xff0c;门槛高”的标签。 本文旨…

【C++】标准模板库 STL 简介

&#x1f9d1;‍&#x1f393;个人主页&#xff1a;简 料 &#x1f3c6;所属专栏&#xff1a;C &#x1f3c6;个人社区&#xff1a;越努力越幸运社区 &#x1f3c6;简 介&#xff1a;简料简料&#xff0c;简单有料~在校大学生一枚&#xff0c;专注C/C/GO的干货分…

JavaScript 的双问号 和 ?. 的含义和作用

1、?. &#xff08;可选链运算符&#xff09; ?. 表示&#xff1a;可选链操作符( ?. )允许读取位于连接对象链深处的属性的值&#xff0c;而不必明确验证链中的每 个引用是否有效。操作符的功能类似于 . 链式操作符&#xff0c;不同之处在于&#xff0c;在引用为空(null 或…

使用端口扫描工具解决开放端口威胁并增强安全性

从暴露网络漏洞到成为入侵者的通道&#xff0c;开放端口可能会带来多种风险向量&#xff0c;威胁到网络的机密性、完整性和可用性。因此&#xff0c;最佳做法是关闭打开的端口&#xff0c;为了应对开放端口带来的风险&#xff0c;网络管理员依靠端口扫描工具来识别、检查、分析…

远程网络监控(RMON)

远程网络监控是一个使 IT 团队能够获得远程网络可见性的过程&#xff0c;它涉及主动监控网络以帮助网络无缝运行&#xff0c;这些监控远程网络的系统提供对性能的实时洞察&#xff0c;及时检测问题并在影响最终用户之前解决问题。这样&#xff0c;远程网络虽然相距遥远&#xf…

用好语言模型:temperature、top-p等核心参数解析

编者按&#xff1a;我们如何才能更好地控制大模型的输出? 本文将介绍几个关键参数&#xff0c;帮助读者更好地理解和运用 temperature、top-p、top-k、frequency penalty 和 presence penalty 等常见参数&#xff0c;以优化语言模型的生成效果。 文章详细解释了这些参数的作用…

zlmediakit实现rtsp流服务器

本次实现是将内存中的H264数据经过zlmediakit实现为rtsp流。 我是用的是CAPI的方式&#xff0c;将zlmediakit作为一个sdk嵌入到自己的程序中而不是作为一个独立的进进程服务。 1.编译完成zkmedialit后会得到bin include lib三个文件夹如图 其中bin中的MediaServer是作为独立的…

Linux作业练习题-解答

作业1&#xff1a;调研数据中心物理机及虚拟机的操作系统版本、虚拟环境使用的 Hypervisor 类型、服务器硬件配置、资源使用情况&#xff08;内存&#xff0f; CPU &#xff0f;磁盘使用率&#xff0c;网络带宽&#xff0c; I / O 速率等&#xff09;&#xff0c;要求调研两个数…

自己实名绑定了几个微信号?赶紧来看看

我们都明白&#xff0c;微信的重要性无处不在&#xff0c;它与我们生活的方方面面紧密相连。如今&#xff0c;微信支付已成为我们日常生活中不可或缺的一部分。无论是购物、用餐&#xff0c;还是日常消费&#xff0c;微信支付都能轻松解决。如果你担心携带现金会有遗失的风险&a…

低代码时代,如何运用JVS低代码表单组件单选与多选组件提升业务效率?

在现代化的数字界面中&#xff0c;组件是不可或缺的一部分。无论是在问卷调查、投票&#xff0c;还是在购物车等场景中&#xff0c;单选和多选组件都扮演着重要角色。它们让用户能够在一系列选项中做出决定&#xff0c;从而提高交互的效率和用户体验。 JVS低代码表单组件中提供…

Apple Vision Pro 开发机申请

申请地址: &#xff08;免费租用形式&#xff09; Developer Kit - visionOS - Apple Developer 上海Apple Lab 互动申请&#xff1a; View - Meet with Apple Experts - Apple Developer (需要完善的产品才能去测试哦) 它是如何工作的 我们将借给你一个Apple Vision Pro开发…

想基于AI变现吗,这个Star有1.8K的开源项目分享给你

公众号「架构成长指南」&#xff0c;专注于生产实践、云原生、分布式系统、大数据技术分享。 前言 在如今AI爆发的时代&#xff0c;每个人都想借着AI这股风&#xff0c;进行变现&#xff0c;今天给大家分享一个开源项目&#xff0c;他可以让你基于AI的能力进行变现 项目介绍 …

Doris中的物化视图(十八)

物化视图就是包含了查询结果的数据库对象&#xff0c;可能是对远程数据的本地 copy&#xff0c;也可能是一个表或多表 join 后结果的行或列的子集&#xff0c;也可能是聚合后的结果。说白了&#xff0c;就是预先存储查询结果的一种数据库对象。 在 Doris 中的物化视图&#xf…