目录
一、springboot返回Jsonson对象
1、新建用户对象,其中密码password字段设置不返回显示,日期字段返回字符串,如下图所示
package com.example.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.util.Date;
/**
* TODO
*
* @author Andy
* @date 2021/4/11 13:14
*/
@Data
public class User {
private String name;
@JsonIgnore
private String password;
private Integer age;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date birthday;
private String desc;
}
2、新建测试controller
package com.example.controller;
import com.example.entity.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
/**
* TODO
*
* @author Andy
* @date 2021/4/11 13:13
*/
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/info")
@ResponseBody
public User getUserInfo(){
User user = new User();
user.setAge(29);
user.setName("andy");
user.setBirthday(new Date());
user.setPassword("123456");
return user;
}
}
3、启动并访问路径
从返回结果可以看出,用户对象中并没有返回密码属性,同时日期格式按照我们制定的规则进行了转换
二、springboot使用devtools进行热部署
1、添加devtools依赖
2、添加以下配置
(1)application.properties
(2)开启自动编译
当我们修改了类文件后,idea不会自动编译,得修改idea设置。
(a)File-Settings-Compiler-Build Project automatically
(b)ctrl + shift + alt + / ,选择Registry,勾上 Compiler autoMake allow when app running
(3)修改configuration
都配置完成后重启测试,不重启情况下修改文件
再次访问:
说明热部署配置已成功!
三、springboot资源文件属性配置
1、资源文件属性配置
(1) pom.xml添加相应依赖
(2) 创建资源文件qiniufile.peoperties
(3) 创建实体对象QiniuFile,并添加相应注解
package com.example.util;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
/**
* TODO
*
* @author Andy
* @date 2021/4/11 13:59
*/
@Configuration
@ConfigurationProperties(prefix="com.example.qiniufile")
@PropertySource(value="classpath:qiniufile.properties")
@Data
public class QiniuFile {
private String accesstoken;
private String key;
}
(4) 用户controller中注入QiniuFile对象,并进行赋值
(5) 访问测试
2、server属性配置
修改application.properties添加如下配置
##########################################################################
#
#Server相关配置
#
##########################################################################
#配置API端口号
server.port=8880
#配置context_path,一般来说,这个配置在正式环境下不配置
server.servlet.context-path=/cms
#配置session最大超时时间
server.session-timeout=60
#该服务绑定IP地址,启动服务器如本机不是该IP地址则抛出异常启动失败
#只有特殊需求的情况下才配置,具体根据各自的业务来设置
server.address=192.168.43.129
配置完成后需要更改访问路径为正确的ip并且上下文路径才能访问:
四、springboot整合模板引擎
1、springboot整合themeleaf
(1) 引入依赖
(2) application.peoperties配置
#thymeleaf模板配置
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
#关闭缓存,及时刷新,上线生产需改为true
spring.thymeleaf.cache=false
(3) 新建html页面
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
Thyme模板引擎
<h1 th:text="${name}">hello world</h1>
</body>
</html>
(4) 新建thymeleafController
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* TODO
* @author Andy
* @date 2021/4/11 12:58
*/
@Controller
@RequestMapping("th")
public class ThymeleafController {
@RequestMapping("/index")
public String index(ModelMap map){
map.addAttribute("name","andythomas");
return "thymeleaf/index";
}
}
需要注意的是这里使用的注解是@Controller,否则会识别不出ModelMap,无法带出传入的值
(5) 启动程序访问
五、springboot异常处理
1、页面跳转形式
(1)新建error.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>捕获全局异常</title>
</head>
<body>
<h1 style="color:red">发生错误:</h1>
<div th:text="${url}"></div>
<div th:text="${exception.message}"></div>
</body>
</html>
(2)新增统一异常拦截
添加 @ControllerAdvice注解。
package com.example.exception;
import com.sun.deploy.net.HttpResponse;
import org.springframework.http.HttpRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* TODO
*
* @author Andy
* @date 2021/4/11 15:29
*/
@ControllerAdvice
public class TRSExceptionHandler {
public static final String TRS_ERROR_VIEW = "thymeleaf/error";
@ExceptionHandler(value = Exception.class)
public Object errorHandler(HttpServletRequest request, HttpServletResponse response, Exception e){
e.printStackTrace();
ModelAndView mav = new ModelAndView();
mav.addObject("exception",e);
mav.addObject("url",request.getRequestURL());
mav.setViewName(TRS_ERROR_VIEW);
return mav;
}
}
启动应用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,都会作用在 被 @RequestMapping 注解的方法上。
@ModelAttribute:在Model上设置的值,对于所有被 @RequestMapping 注解的方法中,都可以通过 ModelMap 获取
(3)制造异常测试
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* TODO
* @author Andy
* @date 2021/4/11 12:58
*/
@Controller
@RequestMapping("err")
public class ErrorController {
@RequestMapping("/error")
public String error(ModelMap map){
int a = 1/0;
return "thymeleaf/error";
}
}
(4)访问查看效果
2、ajax形式
(1) 新建ajax测试页面ajaxerror.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title></title>
<script th:src="@{https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.5.1.min.js}"></script>
</head>
<body>
<h1 >测试ajax错误异常</h1>
<script >
debugger
$.ajax({
url:"/err/getAjaxError",
type:"POST",
async:false,
success:function (data) {
if(data.status==200 && data.msg=="ok"){
alert("success");
}else{
alert("发生异常:"+data.msg);
}
}
});
</script>
</body>
</html>
(2) 新建ajax处理类
package com.example.exception;
import com.example.entity.TRSJsonResult;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* TODO
*
* @author Andy
* @date 2021/4/11 15:29
*/
@RestControllerAdvice
public class TRSAjaxExceptionHandler {
@ExceptionHandler(value = Exception.class)
public TRSJsonResult errorHandler(HttpServletRequest request, HttpServletResponse response, Exception e){
e.printStackTrace();
return TRSJsonResult.errorException(e.getMessage());
}
}
(3) 新建异常处理类
package com.example.entity;
import lombok.Data;
/**
* TODO
*
* @author Andy
* @date 2021/4/11 15:50
*/
@Data
public class TRSJsonResult {
/**
* 响应业务状态
*/
private Integer status;
/**
* 响应信息
*/
private String msg;
/**
* 响应中过的数据
*/
private Object data;
public TRSJsonResult() {
}
public TRSJsonResult(Object data) {
this.status = 200;
this.msg = "OK";
this.data = data;
}
public TRSJsonResult(Integer status, String msg, Object data) {
this.status = status;
this.msg = msg;
this.data = data;
}
public static TRSJsonResult errorException(String msg){
return new TRSJsonResult(555,msg,null);
}
public static TRSJsonResult ok(){
return new TRSJsonResult(null);
}
}
(4) ErrorController添加入口
package com.example.controller;
import com.example.entity.TRSJsonResult;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* TODO
* @author Andy
* @date 2021/4/11 12:58
*/
@Controller
@RequestMapping("err")
public class ErrorController {
@RequestMapping("/error")
public String error(ModelMap map){
int a = 1/0;
return "thymeleaf/error";
}
@RequestMapping("/ajax")
public String ajax(ModelMap map){
return "thymeleaf/ajaxerror";
}
@RequestMapping("/getAjaxError")
@ResponseBody
public TRSJsonResult ajaxerror(ModelMap map){
int a = 1/0;
return TRSJsonResult.ok();
}
}
(5)访问测试
可以看出,在调用ajax请求的时候,进入了统一的异常处理
将业务的实际报错返回给了前台页面
3、统一返回异常的形式,兼容web和ajax
(1)改造异常处理
package com.example.exception;
import com.example.entity.TRSJsonResult;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* TODO
*
* @author Andy
* @date 2021/4/11 15:29
*/
@RestControllerAdvice
public class TRSAjaxExceptionHandler {
public static final String TRS_ERROR_VIEW = "thymeleaf/error";
@ExceptionHandler(value = Exception.class)
public Object errorHandler(HttpServletRequest request, HttpServletResponse response, Exception e){
e.printStackTrace();
// return TRSJsonResult.errorException(e.getMessage());
if(isAjax(request)){
return TRSJsonResult.errorException(e.getMessage());
}else{
ModelAndView mav = new ModelAndView();
mav.addObject("exception",e);
mav.addObject("url",request.getRequestURL());
mav.setViewName(TRS_ERROR_VIEW);
return mav;
}
}
/**
* 判断是否是ajax请求
* @param request
* @return
*/
public static boolean isAjax(HttpServletRequest request){
return (request.getHeader("X-Requested-With")!=null&&
"XMLHttpRequest".equals(request.getHeader("X-Requested-With").toString()));
}
}
(2)测试
六、springboot整合mybatis
(1)事务隔离级别
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。
我们可以看 org.springframework.transaction.annotation.Propagation
枚举类中定义了6个表示传播行为的枚举值:
public enum Propagation {
REQUIRED(0),
SUPPORTS(1),
MANDATORY(2),
REQUIRES_NEW(3),
NOT_SUPPORTED(4),
NEVER(5),
NESTED(6);
}
REQUIRED
:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。SUPPORTS
:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。MANDATORY
:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。REQUIRES_NEW
:创建一个新的事务,如果当前存在事务,则把当前事务挂起。NOT_SUPPORTED
:以非事务方式运行,如果当前存在事务,则把当前事务挂起。NEVER
:以非事务方式运行,如果当前存在事务,则抛出异常。NESTED
:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于REQUIRED
。
指定方法:通过使用 propagation
属性设置,例如:
@Transactional(propagation = Propagation.REQUIRED)
(2)测试
对于下图中的写法先插入用户,后发生异常,在删除用户;在没有事务的控制下是不会进行回滚的
所以需要事务来进行控制,对于增删改的加入如下注解
对于查询的话需要加入如下注解
七、springboot整合redis
(1) pom.xml 中引入相关依赖
<!--引入redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- fastjson依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.15</version>
</dependency>
(2)配置文件中加入redis相关配置
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=20
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=10
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=2
# 连接超时时间(毫秒)
spring.redis.timeout=1000
(3)添加redis工具类
package com.example.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* redisTemplate封装
* @author Andy
*/
@Component
public class RedisUtil {
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* 指定缓存失效时间
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key,long time){
try {
if(time>0){
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key 获取过期时间
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key){
return redisTemplate.getExpire(key,TimeUnit.SECONDS);
}
/**
* 判断key是否存在
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key){
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String ... key){
if(key!=null&&key.length>0){
if(key.length==1){
redisTemplate.delete(key[0]);
}else{
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
//============================String=============================
/**
* 普通缓存获取
* @param key 键
* @return 值
*/
public Object get(String key){
return key==null?null:redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key,Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key,Object value,long time){
try {
if(time>0){
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
}else{
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 递增
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta){
if(delta<0){
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
* @param key 键
* @param delta 要减少几(小于0)
* @return
*/
public long decr(String key, long delta){
if(delta<0){
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
//================================Map=================================
/**
* HashGet
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key,String item){
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
* @param key 键
* @return 对应的多个键值
*/
public Map<Object,Object> hmget(String key){
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String,Object> map){
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String,Object> map, long time){
try {
redisTemplate.opsForHash().putAll(key, map);
if(time>0){
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key,String item,Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key,String item,Object value,long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if(time>0){
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item){
redisTemplate.opsForHash().delete(key,item);
}
/**
* 判断hash表中是否有该项的值
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item){
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item,double by){
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item,double by){
return redisTemplate.opsForHash().increment(key, item,-by);
}
//============================set=============================
/**
* 根据key获取Set中的所有值
* @param key 键
* @return
*/
public Set<Object> sGet(String key){
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key,Object value){
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将数据放入set缓存
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object...values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将set数据放入缓存
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key,long time,Object...values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if(time>0) {
expire(key, time);
}
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
* @param key 键
* @return
*/
public long sGetSetSize(String key){
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除值为value的
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object ...values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
//===============================list=================================
/**
* 获取list缓存的内容
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end){
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
* @param key 键
* @return
*/
public long lGetListSize(String key){
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public Object lGetIndex(String key,long index){
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @return
*/
public boolean lSetMIn(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
expire(key, 60);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @return
*/
public boolean lSetList(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSetList(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index,Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引弹出list中的首条数据
* @param key 键
* @param index 等待时间(秒)
* @return
*/
public Object lPop(String key, long index) {
try {
Object o = redisTemplate.opsForList().leftPop(key, index, TimeUnit.SECONDS);
return o;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 移除N个值为value
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key,long count,Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
}
(4)创建测试controller
package com.example.controller;
import com.alibaba.fastjson.JSONObject;
import com.example.entity.TRSJsonResult;
import com.example.entity.User;
import com.example.util.QiniuFile;
import com.example.util.RedisUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Date;
/**
* TODO
*
* @author Andy
* @date 2021/4/11 13:13
*/
@org.springframework.web.bind.annotation.RestController
@RequestMapping("/redis")
public class RestController {
@Autowired
private RedisUtil redisUtil;
@RequestMapping("/test")
public TRSJsonResult test(){
redisUtil.set("name","andy");
User user = new User();
user.setAge(18);
user.setName("ange");
user.setBirthday(new Date());
redisUtil.set("json:user", JSONObject.toJSONString(user));
return TRSJsonResult.ok(redisUtil.get("json:user"));
}
}
(5)访问进行测试
(6)使用RMD查看数据信息
八、springboot整合定时任务
1、使用注解@EnableScheduling开启定时任务,会自动扫描
2、定义@Component作为组件被自动扫描
package com.example.task;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* TODO
*
* @author Andy
* @date 2021/4/11 18:12
*/
@Component
public class TestTask {
private static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
@Scheduled(fixedRate = 3000)
public void reportCurrentTime(){
System.out.println("当前时间:"+sdf.format(new Date()));
}
}
查看控制台打印
3、表达式生成地址
http://cron.qqe2.com
九、springboot整合异步任务及使用场景
1、使用注解@EnableAsync开启异步,会自动扫描
2、定义@Component@Async作为组件被容器自动扫描
package com.example.task;
import com.example.entity.TRSJsonResult;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Future;
/**
* TODO
*
* @author Andy
* @date 2021/4/11 18:12
*/
@Component
public class AsyncTask {
@Async
public Future<Boolean> doTask1() throws Exception{
long start = System.currentTimeMillis();
Thread.sleep(1000);
long end = System.currentTimeMillis();
System.out.println("任务1耗时:"+(end - start)+"毫秒");
return new AsyncResult<>(true);
}
@Async
public Future<Boolean> doTask2() throws Exception{
long start = System.currentTimeMillis();
Thread.sleep(700);
long end = System.currentTimeMillis();
System.out.println("任务2耗时:"+(end - start)+"毫秒");
return new AsyncResult<>(true);
}
@Async
public Future<Boolean> doTask3() throws Exception{
long start = System.currentTimeMillis();
Thread.sleep(600);
long end = System.currentTimeMillis();
System.out.println("任务3耗时:"+(end - start)+"毫秒");
return new AsyncResult<>(true);
}
}
3.创建测试controller
package com.example.controller;
import com.alibaba.fastjson.JSONObject;
import com.example.entity.TRSJsonResult;
import com.example.entity.User;
import com.example.task.AsyncTask;
import com.example.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Date;
import java.util.concurrent.Future;
/**
* TODO
*
* @author Andy
* @date 2021/4/11 13:13
*/
@org.springframework.web.bind.annotation.RestController
@RequestMapping("/tasks")
public class DoTaskController {
@Autowired
private AsyncTask asyncTask;
@RequestMapping("/test1")
public String test1() throws Exception{
long start = System.currentTimeMillis();
Future<Boolean> a = asyncTask.doTask1();
Future<Boolean> b = asyncTask.doTask2();
Future<Boolean> c = asyncTask.doTask3();
while(!a.isDone()||!b.isDone()||!c.isDone()){
if(a.isDone()&&b.isDone()&&c.isDone()){
break;
}
}
long end = System.currentTimeMillis();
String times = "任务全部完成,总耗时:"+(end-start)+"毫秒";
System.out.println(times);
return times;
}
}
4、访问测试
5、异步执行使用场景
(1)发生短信
(2)发送邮件
(3)App消息推送
(4)节省运维凌晨任务发布时间,提升效率
十、springboot使用拦截器
1、实现HandlerInterceptor接口自定义拦截器
package com.example.config;
import com.example.entity.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* TODO
*
* @author Andy
* @date 2021/4/11 18:54
*/
public class OneInterceptor implements HandlerInterceptor {
/**
* 在请求处理之前进行调用(Controller方法调用之前)
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("被one拦截,放行...");
return true;//如果设置为false时,被请求时,拦截器执行到此处将不会继续操作
//如果设置为true时,请求将会继续执行后面的操作
}
/**
* 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
// System.out.println("执行了TestInterceptor的postHandle方法");
}
/**
* 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
// System.out.println("执行了TestInterceptor的afterCompletion方法");
}
}
2、使用注解@Configuration配置拦截器
3、重写addInterceptors添加需要的拦截器地址
package com.example.config;
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;
/**
* TODO
*
* @author Andy
* @date 2021/4/11 18:54
*/
@Configuration
public class LoginConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册TestInterceptor拦截器
InterceptorRegistration registration = registry.addInterceptor(new OneInterceptor());
registration.addPathPatterns("/**"); //所有路径都被拦截
registration.excludePathPatterns( //添加不拦截路径
"你的登陆路径", //登录
"/**/*.html", //html静态资源
"/**/*.js", //js静态资源
"/**/*.css", //css静态资源
"/**/*.woff",
"/**/*.ttf"
);
}
}
4、访问hello接口,查看运行结果