SpringBoot实践

5.SpringBoot实践

接下来,我们来看看如何用SpringBoot来玩转以前的SSM,我们沿用之前讲解SSM用到的数据库tb_user和实体类User

5.1.整合SpringMVC

虽然默认配置已经可以使用SpringMVC了,不过我们有时候需要进行自定义配置。

5.1.1.修改端口

查看SpringBoot的全局属性可知,端口通过以下方式配置:

# 映射端口
server:
  port: 80

重启服务后测试:

5.1.2.访问静态资源

现在,我们的项目是一个jar工程,那么就没有webapp,我们的静态资源该放哪里呢?

回顾我们上面看的源码,有一个叫做ResourceProperties的类,里面就定义了静态资源的默认查找路径:

默认的静态资源路径为:

  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/
  • classpath:/public

只要静态资源放在这些目录中任何一个,SpringMVC都会帮我们处理。

我们习惯会把静态资源放在classpath:/static/目录下。我们创建目录,并且添加一些静态资源:

重启项目后测试:

5.1.3.添加拦截器

拦截器也是我们经常需要使用的,在SpringBoot中该如何配置呢?

拦截器不是一个普通属性,而是一个类,所以就要用到java配置方式了。在SpringBoot官方文档中有这么一段说明:

If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

翻译:

如果你想要保持Spring Boot 的一些默认MVC特征,同时又想自定义一些MVC配置(包括:拦截器,格式化器, 视图控制器、消息转换器 等等),你应该让一个类实现WebMvcConfigurer,并且添加@Configuration注解,但是千万不要@EnableWebMvc注解。如果你想要自定义HandlerMappingHandlerAdapterExceptionResolver等组件,你可以创建一个WebMvcRegistrationsAdapter实例 来提供以上组件。

如果你想要完全自定义SpringMVC,不保留SpringBoot提供的一切特征,你可以自己定义类并且添加@Configuration注解和@EnableWebMvc注解

总结:通过实现WebMvcConfigurer并添加@Configuration注解来实现自定义部分SpringMvc配置。

首先我们定义一个拦截器:

package cn.clocktt.interceptor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class LoginInterceptor implements HandlerInterceptor {

    private Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.debug("preHandle method is now running!");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.debug("postHandle method is now running!");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.debug("afterCompletion method is now running!");
    }
}

然后,我们定义配置类,注册拦截器:

package cn.clocktt.configuration;

import cn.clocktt.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    /**
     * 通过@Bean注解,将我们定义的拦截器注册到Spring容器
     * @return
     */
    @Bean
    public LoginInterceptor getLoginInterceptor(){
        return new LoginInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 通过registry来注册拦截器,通过addPathPatterns来添加拦截路径
        registry.addInterceptor(this.getLoginInterceptor()).addPathPatterns("/**");
    }
}

结构如下:

接下来运行并查看日志:

你会发现日志中什么都没有,因为我们记录的log级别是debug,默认是显示info以上,我们需要进行配置。

SpringBoot通过logging.level.*=debug来配置日志级别,*号位置表示填写包名

# 设置cn.clocktt包的日志级别为debug
logging:
  level:
    cn.clocktt: debug

再次运行查看:

可以发现拦截器和日志均正常工作

5.2.整合数据库驱动和事务

加入数据库驱动的依赖,SpringBoot并不知道我们用的什么数据库,这里我们选择MySQL:

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

至于事务,SpringBoot中通过注解来控制。就是我们熟知的@Transactional

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public User queryById(Long id){
        return userMapper.selectByPrimaryKey(id);
    }

    @Transactional
    public void deleteById(Long id){
        userMapper.deleteByPrimaryKey(id);
    }
}

5.3.整合连接池

其实,在刚才引入jdbc启动器的时候,SpringBoot已经自动帮我们引入了一个连接池:

HikariCP应该是目前速度最快的连接池了,我们看看它与c3p0的对比:

因此,我们只需要指定连接池参数即可:

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/leyou
    username: root
    password: root

5.4.整合mybatis

我们直接使用通用mapper来整合

通用Mapper的作者也为自己的插件编写了启动器,我们直接引入即可:

<!-- 通用mapper -->
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>2.0.2</version>
</dependency>

只需要配置一下别名扫描和继承通用mapper的接口即可

# mybatis 别名扫描
mybatis:
  type-aliases-package: cn.clocktt.pojo
package cn.clocktt.mapper;

import cn.clocktt.pojo.User;
import tk.mybatis.mapper.common.Mapper;

public interface UserMapper extends Mapper<User> {
}

关于pojo中的成员属性的数据类型一定要使用包装类,不然生成的SQL语句根本都不对。

package cn.clocktt.pojo;
import tk.mybatis.mapper.annotation.KeySql;

import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;

@Table(name = "tb_user")
public class User {
    //@Id代表是主键
    @Id
    //@keySql表示主键是否自增
    @KeySql(useGeneratedKeys = true)
    private Integer id;
    private String name;
    private Integer age;
    //@Transient 表示该字段不是持久化字段,即不不是表中的字段
    @Transient
    private String detail;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getDetail() {
        return detail;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", detail='" + detail + '\'' +
                '}';
    }
}

测试UserMapper接口

引入测试jar包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

package cn.clocktt.mapper;

import cn.clocktt.pojo.User;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import static org.junit.Assert.*;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

    @Autowired
    private UserMapper userMapper;

    public void queryUser(){
        User user = userMapper.selectByPrimaryKey(1);
        System.out.println(user);
    }
}

测试结果:

Service层

package cn.clocktt.service;

import cn.clocktt.mapper.UserMapper;
import cn.clocktt.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    public User findUserById(int id){
        User user = userMapper.selectByPrimaryKey(id);
        return User;
    }
    
    //事务控制
    @Transactional
    public void addUser(User user){
        userMapper.insertSelective(user);
    }

    //事务控制
    @Transactional
    public void deleteUser(int id){
        userMapper.deleteByPrimaryKey(id);
    }
}

Controller层

package cn.clocktt.controller;

import cn.clocktt.pojo.User;
import cn.clocktt.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/user/{id}")
    public User queryUserById(@PathVariable int id){
        User user = userService.findUserById(id);
        return user;
    }

    @RequestMapping("/user/add")
    public String addUser(User user){
        userService.addUser(user);
        return "success";
    }

    @RequestMapping("/user/delete")
    public String deleteUserById(int id){
        userService.deleteUser(id);
        return "success";
    }
}

使用get方式测试
-查询用户

-增加用户

-删除用户

本案例的pom.xml

<?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>cn.clocktt.demo</groupId>
    <artifactId>SpringBootDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--通用mapper-->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.0.2</version>
        </dependency>

        <!--spring测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>
</project>

目录结构

posted @ 2019-01-10 08:25  竹子の云  阅读(178)  评论(0)    收藏  举报