SpringMVC全注解开发

使用SpringMVC技术开发web程序流程
1.创建web工程 (Maven结构)
2.设置tomcat服务器,加载web工程(tomcat插件)
3.导入坐标(SpringMVC+Servlet)
4.定义处理请求的功能类(UserController)
5.设置请求映射(配置映射关系)
6.将SpringMVC设定加载到Tomcat容器中

SpringMVC入门案例

1.导maven坐标


<packaging>war</packaging>

 <dependencies>
            <!-- ServletAPI -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
            <!-- SpringMVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
 </dependencies>

<!-- TomCat插件 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>80</port>
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>

2.创建配置类

@Configuration
@ComponentScan("com.YuZai.controller")
public class SpringmvcConfig {
}
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {

    @Override
    protected WebApplicationContext createServletApplicationContext() {  //SpringMVC对应的容器对象
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(SpringmvcConfig.class);
        return context;
    }

    @Override
    protected String[] getServletMappings() {  //请求是由Tomcat处理还是springMVC处理
        return new String[]{"/"};  //所有请求都归SpringMVC处理
    }

    @Override
    protected WebApplicationContext createRootApplicationContext() {   //spring配置的对应的容器的对象
        return null;
    }
}

AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化web3.0容器的抽象类
AbstractDispatcherServletInitializer提供三个接口方法供用户实现

  1. protected WebApplicationContext createServletApplicationContext()创建Servlet容器,加载SpringMVC对应的bean放入WebApplicationContext对象范围。
  2. protected String[] getServletMappings() 设定SpringMVC对应的请求映射路径,设置为/表示拦截所有请求,任意请求都将转入到SpringMVC进行处理。
  3. protected WebApplicationContext createRootApplicationContext() 如果创建Servlet容器时需要加载非SpringMVC对应的bean,使用当前方法进行。
可以使用它的子类简化开发

public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

3.创建控制器

@Controller
public class UserController {

    @RequestMapping("/save")
    @ResponseBody //将Java对象转换为json格式返回
    public String save(){
        System.out.println("save() Running....");
        return "{鱼仔,18,睡觉}";
    }

}

SpringMVC执行流程

《启动服务器初始化过程》
1. 初始化web容器
2. 执行getServletConfigClasses()方法,创建WebApplicationContext对象
3. 加载SpringMVC配置文件
4. 加载Spring容器中的Bean
5. 加载Controller
6. 执行getServletMappings()方法,所有请求都将通过SpringMVC

《单次请求过程》
1.  发送请求 http://localhost/book
2.  web容器发现所有请求都经过SpringMVC,将请求交给SpringMVC处理
3.	解析请求路径 /book
4./book配置执行对应的方法 selectAll()
5. 	执行selectAll()
6.	检测到有@ResponseBody直接将selectAll()方法的返回值作为响应体返回给请求方

controller控制器

在这里插入图片描述

请求映射路径

@RequestMapping
在这里插入图片描述

参数传递

GET方式传参

请求路径: http://localhost:80/user/save?name=FangYiZe&pw=666999

Controller控制层代码:
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/save")
    @ResponseBody //将Java对象转换为json格式返回
    public String save(String name, String pw){
        System.out.println("save() Running......");
        System.out.println("name"+"=>>>"+name);
        System.out.println("pw"+"=>>>"+pw);
        return "{鱼仔,18,睡觉}";
    }
}

运行结果:
save() Running......
name=>>>FangYiZe
pw=>>>666999

POST方式传参

请求路径: http://localhost:80/user/add
PostMan  x-www-form-urlencoded Body数据
  KEY         VALUE    
  username    FangYiZe 
  password    666999
  sex   	  man

Controller控制层代码:
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping(value = "/add",method = RequestMethod.POST)
    @ResponseBody
    public String add( String username,String password,String sex){
        System.out.println("add() Running......");
        System.out.println("username"+"=>>>"+username);
        System.out.println("password"+"=>>>"+password);
        System.out.println("sex"+"=>>>"+sex);
        return "add() Running...";
    }
}

运行结果:
add() Running......
username=>>>FangYiZe
password=>>>666999
sex=>>>man

POST请求中文乱码处理
POST请求中文乱码处理
为web容器添加过滤器并指定字符集


public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    //乱码处理
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }
}
@RequestParam 获取URL参数

在这里插入图片描述

传实体类参数

请求URL: http://localhost:80/user/test?age=18&username=喜羊羊&hobby=提出方法&book.bookName=喜羊羊的一生&book.price=99.87

controller控制层代码:
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
     @RequestMapping(value = "/test",method = RequestMethod.GET)
     public void test( User user){
        System.out.println("test() Running...");
        System.out.println("user=>>>>>"+user);
    }
}

List集合参数 
例: POST请求 
请求URL: http://localhost:80/user/test02
请求体: 
	KEY			VALUE
  likes			a666
  likes			b666
  likes			c666

controller控制层代码:
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping(value = "/test02",method = RequestMethod.POST)
    public void test02(@RequestParam("likes") List<String> listStr){
        System.out.println("test02() Running...");
        System.out.println("listStr=>>>>>"+listStr);
    }
}

运行结果:
test02() Running...
listStr=>>>>>[a666, b666, c666]
[WARNING] No mapping for POST /user/user/test02

@EnableWebMvc

作用: 开启SpringMVC多项辅助功能。
@EnableWebMvc功能之一: 根据类型匹配对应的类型转换器。

参数传递(Json)
导JSON坐标:
  <!-- JSON -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.3</version>
        </dependency>

开启@EnableWebMvc注解
@Configuration
@ComponentScan("com.YuZai.controller")
@EnableWebMvc
public class SpringmvcConfig {
}

Controller控制层代码:
@Controller
@RequestMapping("/user")
public class UserController {

    //参数传递(JSON)
    @RequestMapping("/test03")
    public void test03(@RequestBody List<String> listStr){
        System.out.println("test03() Running...");
        System.out.println("listStr=>>>>>"+listStr);
    }
}

请求URL: http://localhost:80/user/test03
请求体List JSON格式:  ["aaa","bbb","ccc"]

运行结果:
test03() Running...
listStr=>>>>>[aaa, bbb, ccc]

在这里插入图片描述

POJO实体类的JSON数据

请求URL: http://localhost:80/user/test04

请求体:  嵌套POJO JSON格式
	{
    "username" : "Jack" ,
    "age" : 19,
    "hobby" : "唱,跳,rap,篮球",
    "book" :{
        "bookName" : "投篮的技巧",
        "price" : 100.89
    }
}

Controller控制层代码: 
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/test04")
    public void test04(@RequestBody User user){
        System.out.println("test04() Running...");
        System.out.println("user=>>>>>"+user);
    }
}

运行结果
test04() Running...
user=>>>>>User{username='Jack', age=19, hobby='唱,跳,rap,篮球', book=Book{bookName='投篮的技巧', price=100.89}}


List<POJO> JSON格式

请求URL: http://localhost:80/user/test05

请求体: [{"username":"迪迦超人","age":19,"hobby":"拯救人类","book":{"bookName":"迪迦在地球的一百万年","price":99.99}},{"username":"青蛙王子","age":16}]

Controller层代码:
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/test05")
    public void test05(@RequestBody List<User> listObj){
        System.out.println("test05() Running...");
        System.out.println("listObj=>>>>>"+listObj);
    }
}

运行结果: 
test05() Running...
listObj=>>>>>[User{username='迪迦超人', age=19, hobby='拯救人类', book=Book{bookName='迪迦在地球的一百万年', price=99.99}}, User{username='青蛙王子', age=16, hobby='null', book=null}]



@RequestBody

在这里插入图片描述

在这里插入图片描述

参数传递(日期类型)
@DateTimeFormat 指定日期格式


请求URL: http://localhost:80/user/test06?date1=2022/02/02&date2=2022-01-01&date3=2022/03/14 11:35:59

Controller控制成代码:
@Controller
@RequestMapping("/user")
public class UserController {
 @RequestMapping("/test06")
    public void test06(Date date1, @DateTimeFormat(pattern = "yyyy-MM-dd") Date date2 , @DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss") Date date3 ){
        System.out.println("test06() Running..." );
        System.out.println( "Data1=>>"+ date1 );
        System.out.println( "Data2=>>"+ date2 );
        System.out.println( "Data3=>>"+ date3 );
    }
}

运行结果: 
test06() Running...
Data1=>>Wed Feb 02 00:00:00 CST 2022
Data2=>>Sat Jan 01 00:00:00 CST 2022
Data3=>>Mon Mar 14 11:35:59 CST 2022

请求与响应

 响应页面
 响应数据
 	文本数据
 	json数据

响应页面、跳转页面  (直接返回页面名称)

 @RequestMapping(value = "/test001",method = RequestMethod.GET)
    public String test001(){
        System.out.println("test001() Running...");
          return "index.jsp";
    }

报错:[WARNING] No mapping for GET /pages/books.html

原因: 被SpringMVC拦截了所有请求
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};  //这就是问题点
    }
}

解决方法: 不走SpringMVCTomCat  (设置对静态资源的访问放行)
@Configuration
public class SpringmvcSupport extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) { //作用:添加资源的过滤
        //当访问 /pages/资源名 时,不通过springMVC,直接访问 /pages/ 下的资源。
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        //同理
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
        
    }
}



响应纯文本数据  

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

    @RequestMapping(value = "/test002",method = RequestMethod.GET)
    @ResponseBody
    public String test002(){
        System.out.println("test002() Running...");
        return "response text";
    }

}

响应POJO对象
@Controller
@RequestMapping("/user")
public class UserController {
	@RequestMapping("/test003")
    @ResponseBody
    public User test003(){
        User user = new User();
        user.setUsername("小小怪");
        user.setHobby("挨揍");
        return user;
    }
   
}

响应POJO集合

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/test004")
    @ResponseBody
    public List<User> test004(){
        User user1 = new User();
        User user2 = new User();
        user1.setUsername("翼龙");
        user2.setUsername("霸王龙");
        ArrayList<User> users = new ArrayList<>();
        users.add(user1);
        users.add(user2);
        return users;
    }
}

REST风格

REST(Representational State Transfer) 表现形式状态转换
	传统风格资源描述形式
		http://localhost/user/getById?id=1
		http://locahlost/user/saveUser
	REST风格描述形式
		http://localhost/user/1
		http://localhost/user
优点:
	隐藏资源的访问路径,无法通过地址得知对资源是可何种操作
	简化书写

按照REST风格访问资源时使用行为动作区分对资源进行了何种操作

http://localhost/users   查询全部用户信息 GET (查询)
http://lcoalhost/users/1 查询指定用户信息 GET (查询)
http://localhost/users   添加用户信息 POST (新增/保存)
http://localhost/users   修改用户信息 PUT (修改/更新)
http://localhost/users/1 删除用户信息 DELETE (删除)

上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范。
描述模块的名称通常是用复数,也就加s的格式描述,表示此类资源,而非单个资源,例如: users、books...

根据REST风格对资源进行访问称为RESTful
REST 案例

案例 GET带参
URL: http://localhost:80/user/9999
Controller:
@Controller
@RequestMapping("/user")
public class UserController {
	 @RequestMapping(value = "/{id}", method = RequestMethod.GET)
	    public void testA(@PathVariable int id){
	        System.out.println("testA Running... ");
	        System.out.println("id =>>> " +id );
	    }
}
运行结果:
	testA Running... 
	id =>>> 9999

-----------------------------------------------------------------
案例 POST请求 带请求体 ({"username":"大鲨鱼","age":998,"hobby":"大吃特吃" })
URL: http://localhost:80/user
Controller:
@Controller
@RequestMapping("/user")
public class UserController {
	@RequestMapping(method = RequestMethod.POST)
    public void testC(@RequestBody User user){
        System.out.println("执行添加操作,增加" +user);
    }
}
运行结果:
	执行添加操作,增加User{username='大鲨鱼', age=998, hobby='大吃特吃', book=null}

-----------------------------------------------------------------

案例 PUT请求 带请求体 ({"username":"大大怪","age":112,"hobby":"敢作敢当" })
URL: http://localhost:80/user
Controller:
@Controller
@RequestMapping("/user")
public class UserController {
	@RequestMapping(method = RequestMethod.PUT)
    public void testE(@RequestBody User user){
        System.out.println("执行修改操作,修改"+user);
    }
}
运行结果:
	执行修改操作,修改User{username='大大怪', age=112, hobby='敢作敢当', book=null}
接收参数的三种方式

至此,接收参数的方式一共有三种,分别是: @RequestBody、@RequestParam、@PathVariable,第一种是接收请求体参数,第二种是接收URL传参例: http://localhost:80/user/test?age=18&username=喜羊羊 , 第三种是接收路径参数例: http://localhost:80/user/1

在这里插入图片描述

RESTful快速开发
@RestController
@RequestMapping("/user002")
public class User002Controller {

    @GetMapping("/{id}")    //测试URL:http://localhost:80/user002/1
    public User selectById(@PathVariable int id ){
        User user = new User();
        user.setUsername("暴龙");
        return user;
    }

    @PostMapping   //测试URL:http://localhost:80/user002  请求体: {"username":"暴龙战士","hobby":"炫饭"}
    public void addUser(@RequestBody User user){
        System.out.println( "添加新成员=>>>"+user );
    }

    @DeleteMapping  //测试URL:http://localhost:80/user002?id=9
    public void deleteUser(@RequestParam int id){
        System.out.println("删除成员=>>>"+id);
    }

    @PutMapping("/{id}") //测试URL:http://localhost:80/user002/6
    public void updateUser(@RequestBody User user,@PathVariable int id){
        System.out.println( "修改id为"+id+"的成员=>>>"+user );
    }

}


静态资源访问放行
记得将此配置类加载到SpringMVC容器中

@Configuration
public class SpringmvcSupport extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) { //作用:添加资源的过滤
        //当访问 /pages/资源名 时,不通过springMVC,直接访问 /pages/ 下的资源。
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        //同理
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
        
    }
}

SSM整合

SSM整合流程
 1.创建工程
 2.SSM整合
 	Spring
 		SpringConfig
 	MyBatis
 		MybatisConfig
 		JdbcConfig
 		jdbc.properties
 	SpringMVC
 		ServletConfig
 		SpringMvcConfig
3.功能模块
	表与实体类
	dao(接口+自动代理)
	service(接口+实现类)
		业务层接口测试(整合JUnit)
	controller
		表现层接口测试(PostMan)
整合配置

		<packaging>war</packaging>
		
        <!-- SpringMVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>

        <!-- Spring整合jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>

        <!-- Spring整合Test -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>

        <!-- MyBatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>

        <!-- MyBatis-Spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>


        <!-- MySql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.29</version>
        </dependency>

        <!-- druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.11</version>
        </dependency>

        <!-- junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- ServletAPI -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- JSON -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>

    </dependencies>

    <!-- TomCat插件 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.1</version>
                <configuration>
                    <port>80</port>
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>

 

// 此类是Spring配置类。

@Configuration
@ComponentScan({"com.YuZai.service"})
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MyBatisConfig.class})
@EnableTransactionManagement //开启事务
public class SpringConfig {
}

resources/jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/SpringMVCSSM_db
jdbc.username=root
jdbc.password=0000000
com/YuZai/config/JdbcConfig.java

public class JdbcConfig {

    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;


    @Bean  //将返回值加载到Spring的IOC容器
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);

        return dataSource;
    }
	 //事务管理器
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager ds = new DataSourceTransactionManager();
        ds.setDataSource(dataSource);
        return ds;
    }
}

//Spring整合MyBatis

public class MyBatisConfig {

    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){  //dataSource由Spring自动装配
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setTypeAliasesPackage("com.YuZai.domain");
        return factoryBean;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        msc.setBasePackage("com.YuZai.dao");

        return msc;
    }

}
com/YuZai/config/ServletConfig.java

public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

	 //乱码处理
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }
}

com/YuZai/config/SpringMvcConfig.java

@Configuration
@ComponentScan("com.YuZai.controller")
@EnableWebMvc
public class SpringMvcConfig {
}
功能模块开发
domain

public class Book {
    private Integer id ;
    private String type;
    private String bookName;
    private String description;
	构造器方法...
	getter,setter方法....
	toString....
}
dao

// 增删改查

public interface BookDao {

    //利用mybatis的自动代理写实现

    @Select("SELECT * FROM tab_book WHERE id=#{id}")  // #{方法的形参名}
    public Book selectById(Integer id);

    @Select("SELECT * FROM tab_book ")
    public List<Book> selectAll();

    @Insert("INSERT tab_book( TYPE,book_name,description ) VALUES ( #{type},#{bookName},#{description} ); ")  //#{POJO的属性}
    public void addBook(Book book);

    @Update("UPDATE tab_book SET TYPE=#{type},book_name=#{bookName},description=#{description} WHERE id=#{id} ; ")  //#{POJO的属性}
    public void updateBook(Book book);

    @Delete("DELETE FROM tab_book WHERE id=#{id} ;")  //#{方法的形参名}
    public void deleteBook(Integer id);

}
service 

// 业务层接口

@Transactional
public interface BookService {
    public Book selectById(Integer id);
    public List<Book> selectAll();
    public boolean addBook(Book book);
    public boolean updateBook(Book book);
    public boolean deleteBook(Integer id);
}

service.impl

@Service
public class BookServiceImpl implements BookService {

    @Autowired
    private BookDao bookDao;

    @Override
    public Book selectById(Integer id) {
        Book book = bookDao.selectById(id);
        return book;
    }

    @Override
    public List<Book> selectAll() {
        List<Book> books = bookDao.selectAll();
        return books;
    }

    @Override
    public boolean addBook(Book book) {
        bookDao.addBook(book);
        return true;
    }

    @Override
    public boolean updateBook(Book book) {
        bookDao.updateBook(book);
        return true;
    }

    @Override
    public boolean deleteBook(Integer id) {
        bookDao.deleteBook(id);
        return true;
    }
}

controller

package com.YuZai.controller;

@RestController
@RequestMapping("/books")
public class BookController {

    @Autowired
    private BookServiceImpl bookService;

    @GetMapping
    public List<Book> selectAll(){   // 测试URL: http://localhost:80/books
        List<Book> books = bookService.selectAll();
        return books;
    }

    @GetMapping("/{id}")
    public Book selectById(@PathVariable Integer id){
        Book book = bookService.selectById(id);
        return book;
    }

    @PostMapping    // 测试URL: http://localhost:80/books  post 请求体:{"type":"动漫类","bookName":"迪迦爱学习","description":"超励志"}
    public boolean addBook(@RequestBody Book book){
        boolean b = bookService.addBook(book);
        return b;
    }

    @PutMapping    // 测试URL:http://localhost:80/books  Put 请求体:{"type":"动漫类","bookName":"打大怪将军","description":"超腻害","id":"4"}
    public boolean updateBook(@RequestBody Book book){
        boolean b = bookService.updateBook(book);
        System.out.println(book);
        return b;
    }

    @DeleteMapping("/{id}")      //测试URL:http://localhost:80/books/5 DELETE
    public boolean deleteBook(@PathVariable Integer id){
        boolean b = bookService.deleteBook(id);
        return b;
    }

}
接口测试

//Spring整合Junit

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class BookServiceTest {

    @Autowired
    private BookServiceImpl bookService;

    @Test
    public void TestSelectById(){
        Book book = bookService.selectById(1);
        System.out.println(book);
    }

    @Test
    public void TestSelectAll(){
        List<Book> books = bookService.selectAll();
        System.out.println(books);
    }

 

}

表现层数据封装
后端统一数据模型传给前端的。

设置统一数据返回结果类:   
public class Result{
	private Object data;   //封装数据
	private Integer code;  //状态码
	private String message; //消息
	
}
需要注意的是: 这就是前后端通讯的协议,没有固定格式,Result类中的字段并不固定,根据需要增减,提供构造方法。


public class Code {

    public static final Integer SELECT_OK = 20011;
    public static final Integer ADD_OK = 20021;
    public static final Integer DELETE_OK = 20031;
    public static final Integer UPDATE_OK = 20041;

    public static final Integer SELECT_ERR = 20010;
    public static final Integer ADD_ERR = 20020;
    public static final Integer DELETE_ERR= 20030;
    public static final Integer UPDATE_ERR = 20040;
    
}

//表现层
@RestController
@RequestMapping("/books")
public class BookController {

    @Autowired
    private BookServiceImpl bookService;

    @GetMapping
    public Result selectAll(){   // 测试URL: http://localhost:80/books GET
        List<Book> books = bookService.selectAll();
        System.out.println(books);
        Integer code = books.size() != 0 ? Code.SELECT_OK : Code.SELECT_ERR;
        String msg = books.size() != 0 ? "" : "查询数据失败,请重试!";
        return new Result(books,code,msg);
    }

    @GetMapping("/{id}")
    public Result selectById(@PathVariable Integer id){   // 测试URL: http://localhost:80/books/1   GET
        Book book = bookService.selectById(id);
        Integer code = book != null ? Code.SELECT_OK : Code.SELECT_ERR;
        String msg = book != null ? "" : "查询数据失败,请重试!";
        return new Result(book,code,msg);
    }

    @PostMapping    // 测试URL: http://localhost:80/books  post 请求体:{"type":"动漫类","bookName":"迪迦爱学习","description":"超励志"}
    public Result addBook(@RequestBody Book book){
        boolean b = bookService.addBook(book);
        return new Result(b,b?Code.ADD_OK:Code.ADD_ERR);
    }
}

异常处理
程序开发中不可避免会遇到异常。 
	程序正常运行时理应返回统一格式的Result封装数据。
	但若是出现异常返回给前端的就是一堆html代码。

异常得分类处理:
	出现异常现象的常见位置与常见诱因如下:
	框架内部抛出的异常 :因使用不合规导致
	数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)
	业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等)
	表现层抛出的异常: 因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)
	工具类拋出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)

解决思想:
	数据层、业务层、表现层均出现异常,异常处理代码书写在哪一层? 
	解:全部往上抛,抛到表现层进行处理。
	表现层每个方法都得进行异常处理,代码书写量巨大,如何解决?
	解:AOP思想。

以上 异常分类处理、统一表现层处理、AOP处理的操作,SpringMVC已经做了封装。
	----- 异常处理器!
异常处理器

集中的、统一的处理项目中出现的异常。

package com.YuZai.controller;
//异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {

    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex){
        return new Result(null,null,"后台出错了");
    }

}


项目异常分类
	业务异常(BusinessException)
		规范的用户行为产生的异常
		不规范的用户行为操作产生的异常
	系统异常(SystemException)
		项目运行过程中可预计且无法避免的异常
	其他异常(Exception)
		编程人员未预期到的异常

项目异常处理方案
	业务异常(BusinessException)
	 	◆发送对应消息传递给用户, 提醒规范操作
	系统异常(SystemException)
		◆发送固定消息传递给用户,安抚用户.
		◆发送特定消息给运维人员,提醒维护
		◆记录日志
	其他异常(Exception)
		◆发送固定消息传递给用户,安抚用户
		◆发送特定消息给编程人员,提醒维护(纳入预期范围内)
		◆记录日志

自定义业务型异常

package com.YuZai.exception;

public class BusinessException extends RuntimeException{
    private Integer code;

    public Integer getCode() {return code;    }

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

    public BusinessException(String message, Integer code) {
        super(message);
        this.code = code;
    }

    public BusinessException(String message, Throwable cause, Integer code) {
        super(message, cause);
        this.code = code;
    }
}
自定义系统型异常

package com.YuZai.exception;

public class SystemException extends RuntimeException{
    private Integer code;

    public Integer getCode() { return code;  }

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

    public SystemException(String message, Integer code) {
        super(message);
        this.code = code;
    }

    public SystemException(String message, Throwable cause, Integer code) {
        super(message, cause);
        this.code = code;
    }

}
自定义异常编码

public class Code {
    public static final Integer SYSTEM_ERR = 50001;
    public static final Integer BUSINESS_ERR = 60001;
    public static final Integer SYSTEM_UNKNOW_ERR = 59999;
}

模拟激活异常

package com.YuZai.service.impl;

@Service
public class BookServiceImpl implements BookService {

    @Autowired
    private BookDao bookDao;
		
	@Override
    public Book selectById(Integer id) {
        //模拟业务异常  测试URL:http://localhost:80/books/200
        if(id==200){
            throw new BusinessException("禁止违规操作!",Code.BUSINESS_ERR);
        }
        //模拟未知类异常   测试URL:http://localhost:80/books/300
        if (id==300){
            throw new ArithmeticException();
        }
        //将可能出现的异常进行包装,转换成自定义异常  测试URL:http://localhost:80/books/1
        try {
            System.out.println(2/0);
        }catch (ArithmeticException e){
            throw new SystemException("系统繁忙,请稍后重试!",e, Code.SYSTEM_ERR);
        }

        Book book = bookDao.selectById(id);
        return book;
    }
		
}

异常处理器 拦截并处理异常

package com.YuZai.controller;

@RestControllerAdvice
public class ProjectExceptionAdvice {

    /**
     * 处理系统类异常
     * @param ex
     * @return
     */
    @ExceptionHandler(SystemException.class)
    public Result doSystemException(SystemException ex){
        //记录日志
        //通知运维
        //发邮件给开发,将ex对象发给开发
        //return信息给前端
        return new Result(null,ex.getCode(),ex.getMessage());
    }

    /**
     * 业务类异常
     * @param ex
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    public Result doBusinessException(BusinessException ex){
        //返回信息给前端
        return new Result(null,ex.getCode(),ex.getMessage());
    }

    /**
     * 其他类异常
     * @param ex
     * @return
     */
    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex){
        //记录日志
        //通知运维
        //发邮件给开发,将ex对象发给开发
        //return信息给前端
        return new Result(null,Code.SYSTEM_UNKNOW_ERR,"系统维护,请稍后再试! ");
    }

}

异常处理器效果对比

{
    "data": null,
    "code": 50001,
    "message": "系统繁忙,请稍后重试!"
}

{
    "data": 
        {
            "id": 1,
            "type": "搞笑类",
            "bookName": "懒羊羊考试",
            "description": "小孩子喜欢看"
        },
    "code": 20011,
    "message": ""
}
拦截器
拦截器是一种动态拦截方法调用的机制
	作用:在指定的方法调用前后执行预先设定后的代码
		 阻止原始方法的执行

拦截器与过滤器区别
	归属不同:Filter属于Servlet技术,Interceptor属于SprinigMVC技术
	拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强
入门案例: 步骤一

// 拦截器  (为SpringMVC服务,得加载到SpringMvc容器中)

package com.YuZai.controller.interceptor;

@Component
public class ProjectInterceptor implements HandlerInterceptor {

    @Override  // preHandle()表示拦截原始操作之前运行的代码
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle() Running...");
        return true;  // 如果返回false,表示终止原始操作的进行,自然的后面的postHandle()、afterCompletion()也不会执行。
    }

    @Override // postHandle()表示拦截原始操作之后运行的代码
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle() Running...");
    }

    @Override //
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion() Running...");
    }
}
入门案例:步骤二

package com.YuZai.config;

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");  //测试URL:http://localhost/pages/books.html
    }

    @Autowired
    private ProjectInterceptor projectInterceptor;
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
    	//进行具体的拦截器配置
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    }

}
简化配置类开发小技巧

SpringMvcSupport
SpringMvcConfig

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");  //测试URL:http://localhost/pages/books.html
    }

    @Autowired
    private ProjectInterceptor projectInterceptor;
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    }
}

@Configuration
@ComponentScan({"com.YuZai.controller","com.YuZai.config"})
@EnableWebMvc
public class SpringMvcConfig {
}

可以变为:  
	缺点: 入侵性较强,因为实现了接口,此程序就和Spring强绑定了(这个类跟Spring的API关联在一起了)
@Configuration
@ComponentScan({"com.YuZai.controller","com.YuZai.config"})
@EnableWebMvc
public class SpringMvcConfigF implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    }
}
	

拦截器的执行流程:
在这里插入图片描述

拦截器参数


@Override  
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true; 
    }

参数:
	request:请求对象
	response:响应对象
	handler:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装 (可以这么说:拿到了handler对象就可以操作原始执行的那个方法)
返回值: 
	返回值为false,被拦截的处理器将不执行。

 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
参数:
	ModelAndView (现在的开发模式已经不使用它了) 如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整。 

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
参数:
	Exception (完全可以通过SpringMVC替换这里进行的操作)如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理。

当配置多个拦截器时,形成拦截器链


// 当配置多个拦截器时,形成拦截器链
com/YuZai/controller/interceptor/ProjectInterceptor02.java
@Component
public class ProjectInterceptor02 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle02() Running...");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle02() Running...");
    }

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

com/YuZai/config/SpringMvcSupport.java
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Autowired
    private ProjectInterceptor projectInterceptor;
    @Autowired
    private ProjectInterceptor02 projectInterceptor02;
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
        registry.addInterceptor(projectInterceptor02).addPathPatterns("/books","/books/*");
    }

}

在这里插入图片描述

拦截器链的运行顺序
	preHandle: 与配置顺序相同,必定运行
	postHandle: 与配置顺序相反,可能不运行
	afterCompletion:与配置顺序相反,可能不运行

例: 
	preHandle() Running...
	preHandle02() Running...
	postHandle02() Running...
	postHandle() Running...
	afterCompletion02() Running...
	afterCompletion() Running...

  • 9
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值