SpringBoot常用技巧,开箱即用

179 阅读7分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情(juejin.cn/post/716729… "juejin.cn/post/716729…")

1. 自定义日期转换器

  • 首先写一个转换日期的util工具类
  • 这里边可以转换 yyyy-MM-dd yyyy-MM-dd HH:mm:ss 两种格式的日期
package cn.yufire.wms.util;

import cn.yufire.wms.util.EmptyUtils;
import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * <p>
 * Description:  自定义日期转化器
 * </p>
 *
 * @author yufire
 * @version v1.0.0
 * @see cn.yufire.wms.config
 * @since 2020-05-12 16:27:14
 */
public class DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String str) {
        if (EmptyUtils.isEmpty(str) || str.length() <= 0) {
            return null;
        } else {
            Date date = null;
            try {
                date = new SimpleDateFormat(str.length() > 11 ? "yyyy-MM-dd HH:mm:ss" : "yyyy-MM-dd").parse(str);
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return date;
        }
    }
}
  • 写一个配置类 继承 WebMvcConfigurerAdapter
  • 重写 addFormatters 方法
  • 配置日期转换类
package cn.yufire.wms.config;

import cn.yufire.wms.util.DateConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * <p>
 * Description:  配置日期转换器
 * </p>
 *
 * @author yufire
 * @version v1.0.0
 * @see cn.yufire.wms.config
 * @since 2020-05-12 16:27:02
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new DateConverter());
    }
}

这样就可以实现全局日期转换了!


2. 解决跨域问题

什么是跨域问题 ?

在浏览器端进行不同源的 Ajax 请求时会出现跨域问题,那么什么是跨域,如何解决跨域呢?

什么是同源?

所谓同源是指,域名,协议,端口均相同

全局解决跨域
  • 写一个配置类
  • 在IOC容器中创建一个 Bean WebMvcConfigurer
  • 重写 addCorsMappings 方法 并设置参数
package cn.yufire.dining.back.confing;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


/**
 *
 * <p>
 * Description:跨域请求配置
 * </p>
 *
 * @author yufire
 * @version v1.0.0
 * @since 2020-03-05 22:43:21
 * @see cn.yufire.dining.back.confing
 *
 */
@Configuration
public class CORSConfiguration {
    
//addMapping:配置可以被跨域的路径,可以任意配置,可以具体到直接请求路径。
//allowedMethods:允许所有的请求方法访问该跨域资源服务器,如:POST、GET、PUT、DELETE等。
//allowedOrigins:允许所有的请求域名访问我们的跨域资源,可以固定单条或者多条内容,如:"http://www.baidu.com",只有百度可以访问我们的跨域资源。
//allowedHeaders:允许所有的请求header访问,可以自定义设置任意请求头信息,如:"X-YAUTH-TOKEN"

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("*")
                        .allowedMethods("GET", "POST", "DELETE", "PUT","PATCH")
                        .allowedHeaders("*")
                        .allowCredentials(true)
                        .maxAge(3600);
            }
        };
    }
}
单个Controller解决跨域
  • 可以直接使用注解实现
  • CrossOrigin
package cn.yufire.wms.controller;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@CrossOrigin(origins = "*",maxAge = 3600)
public class TestController {
    
    @GetMapping("/hello")
    public String hello(){
        return "hello";
    }
    
}

3.拦截器

  • 写一个配置类
  • 实现 WebMvcConfigurer
  • 重写
package cn.yufire.dining.back.confing;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 拦截器
 */
@Configuration
class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册TestInterceptor拦截器
        InterceptorRegistration registration = registry.addInterceptor(new AdminInterceptor());
        //所有路径都被拦截
        registration.addPathPatterns("/**");
        // 不拦截请求的数组
        String[] excludePaths = {"/index", "/login/adminLogin", "/login", "/**/*.html", "/**/*.js", "/**/*.css", "/**/*.woff", "/**/*.ttf"};
        // 不拦截哪些请求
        registration.excludePathPatterns(excludePaths);
    }
}
  • 写一个拦截器类
package cn.yufire.dining.back.confing;

import cn.yufire.dining.back.util.ResultUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.servlet.HandlerInterceptor;

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

/**
 * 拦截器
 */
class Interceptor implements HandlerInterceptor {

    /**
     * 转换json的类
     */
    private ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 在请求处理之前进行调用(Controller方法调用之前)
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //服务器地址
        String strBackUrl = "http://" + request.getServerName()
                + ":"
                //端口号
                + request.getServerPort()
                //项目名称
                + request.getContextPath()
                //请求页面或其他地址
                + request.getServletPath()
                //参数
                + "?" + (request.getQueryString());

        // 获取请求头信息中的数据
        String token = request.getHeader("token");
        if (token ** null) {
            // return true代表可以往下走 
            // 反则不可以往下走 可以用下边的方法给前端返回json数据
            // 如果是同步请求的话可以直接重定向 或 转发
            returnJson(response, "去登陆!!!");
            return false;
        } else {
            return true;
        }
    }

    /**
     * 返回给前端的json串  提示用户没有登陆
     *
     * @param response
     * @param msg
     * @throws Exception
     */
    public void returnJson(HttpServletResponse response, String msg) throws Exception {
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=utf-8");
        try {
            String msgJson = objectMapper.writeValueAsString(ResultUtil.error(msg));
            writer = response.getWriter();
            writer.print(msgJson);
        } catch (IOException e) {
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

}

4. 获取RestTemplate

  • 写一个配置类
package cn.yufire.dining.back.confing;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

/**
 * 
 * <p>
 * Description: 获取一个 RestTemplate 对象 放入 IOC容器中
 * </p>
 * 
 * @author yufire
 * @version v1.0.0
 * @since 2020-03-06 12:37:04
 * @see cn.yufire.dining.back.confing
 *
 */
@Component
public class RestTemplateConfig {

        @Bean
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
}

5. SpringBoot开机启动的类

  • 这个类会在SpringBoot项目启动的时候进行加载
  • 你可以在 run 方法中执行自己的业务
package cn.yufire.wms.config;

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class PowerOnClass implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("Spring Boot 启动了");
        // 你要干的事情...
    }
}


6.SpringBoot异步任务

  • SpringBoot异步任务可用于 邮件发送 验证码发送 等等 执行时间较长的任务
  • 方法的返回值必须是 void !!!
  • 首先在 SpringBoot主类中使用 @EnableAsync 注解开启异步任务
package cn.yufire.app;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//开启异步方法
@EnableAsync
@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

}

  • 在要使用异步任务的方法上加上 @Async 注解即可
  • 这边创建了一个 service 模拟真实环境
Service
package cn.yufire.skills.service;

public interface AsyncService {
    void asyncTest() throws InterruptedException;
}

ServiceImpl
package cn.yufire.skills.service.impl;

import cn.yufire.skills.service.AsyncService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class AsyncServiceImpl implements AsyncService {

    @Async
    @Override
    public void asyncTest() throws InterruptedException {
        Thread.sleep(3000);
        System.out.println("执行完成!");
    }
}

Controller
package cn.yufire.skills.controller;

import cn.yufire.skills.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AsyncController {

    @Autowired
    private AsyncService asyncService;

    @GetMapping("/")
    public String asyncTest() throws InterruptedException {
        asyncService.asyncTest();
        return "success";
    }

}
  • 写好之后打开网页直接访问该接口
  • 会发现 该接口会直接给我们返回结果 并没有等待那个 线程睡眠的3秒钟
  • 测试结果

img


7. Thymeleaf的HTML头信息

  • xmlns="http://www.w3.org/1999/xhtml"
  • xmlns:th="http://www.thymeleaf.org"
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf头信息</title>
</head>
<body>
    <span th:text="session.user.usreName"></span>
</body>
</html>

8. JDBC开箱即用

注意

添加了 spring-boot-starter-jdbc 依赖后必须在配置文件中填写数据库连接信息 否则项目启动报错

  1. 创建SpringBoot项目
  2. 添加依赖
<!--SpringBoot的Web依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--SpringBoot的JDBC依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--MySQL驱动依赖-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
  1. 添加配置文件
spring:
  datasource: # mysql的配置
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://ip:端口/db_name?serverTimezone=Asia/Shanghai
    username: root
    password: root
  1. 创建Controller
package cn.yufire.skills.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@RestController
public class JdbcTemplateController {

    /**
     * Spring为我们高度封装的 jdbc操作模板
     */
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @GetMapping("/")
    public List<Map<String, Object>> getUsers() {
        String sql = "select * from jy_user";
        // 使用 queryForList 查询出来数据集合
        List<Map<String, Object>> users = jdbcTemplate.queryForList(sql);
        return users;
    }

}

  1. 测试
  2. 可以看到数据库的信息已经被我们查询出来了

img

  1. 其他的 DML 操作 可以使用 query 方法进行

JdbcTemplate模板操作详解 传送门 还没开始写

9. Redis开箱即用

  • 创建SpringBoot项目

  • 添加依赖

<!--SpringBoot的Web依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--SpringBoot的Redis依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • 配置文件添加Reids信息
spring:
  redis:
    database: 0
    host: 192.168.244.106
    port: 6379
    password: root
  • 创建 Controller
package cn.yufire.skills.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RedisTemplateController {

    /**
     * Spring为我们封装的 redis操作摸板
     */
    @Autowired
    private RedisTemplate<String, String> redisTemplate;


    @GetMapping("/get/{key}")
    public String getKey(@PathVariable("key") String key) {
        return redisTemplate.opsForValue().get(key);
    }

    @GetMapping("/set")
    public String getKey(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
        return "success";
    }

}

  • 测试 结果

img


10. 自定义页面映射

  • 创建配置类
package cn.yufire.skills.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 * <p>
 * Description:  Web访问路径配置类
 * </p>
 *
 * @author yufire
 * @version v1.0.0
 * @see cn.yufire.skills.config
 * @since 2020-05-12 19:45:42
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    @Override
    protected void addViewControllers(ViewControllerRegistry registry) {
        // 你要访问的路径  :   真实的页面 
        // 页面位于 templates下
        registry.addViewController("/").setViewName("index");
        // 可以添加多个
        //registry.addViewController("/").setViewName("index");
        
    }
}
  • 启动项目 测试

img

11. SpringBoot中的事务

package cn.yufire.jysong.service.impl;

@Service
// 也可也放在类上
//@Transactional
public class Song_KuGouServiceImpl extends CommonClass implements Song_KuGouService {

    @Autowired
    private JySongInfoKgMapper kgMapper;

    @Autowired
    private JySongLyricKgMapper lyricKgMapper;


    @Override
    // 使用 Transactional注解开启事务  
    // rollbackFor指定出现哪些异常才进行回滚 
    // Java中已经定义的异常可以不指定 如果是自定义的异常需要指定
    @Transactional(rollbackFor = Exception.class)
    public JySongInfoWyy addSongInfo(JySongInfoWyy jySongInfoWyy) {
        return null;
    }

}

@Transactional注解 配置说明

属性名说明
name当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器。
propagation事务的传播行为,默认值为 REQUIRED。
isolation事务的隔离度,默认值采用 DEFAULT。
timeout事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
read-only指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
rollback-for用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。
no-rollback- for抛出 no-rollback-for 指定的异常类型,不回滚事务。

12. SpringBoot多环境配置

  • 在resources下创建 application-dev.yml 或 application-xxx-yml
  • 在主配置文件中激活
spring:
  profiles:
    active: dev  # 该 dev 就是 application-dev.yml

作者:yufire © yufirem@vip.qq.com