一.使用lombok插件
在平时的代码编写中,我们要编写很多javabean,pojo等等的对象类,而且还要对各种属性生成各种的setxxx,getxxx,tostring,hashcode,equal等方法,这些都是一些规定死的模板方法,或者你可能会说我用idea自动帮我生成的,但是这样也会使类中的代码增多,而使用lombok就可以一句这样的代码也不用编写就可以达到自己想要的效果。
使用:
1.首先在maven的pom.xml中加入lombok的坐标依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2.依赖进来之后还要增加一个插件
下载下来重启idea就可。
3.在自己创建的javabean中使用set方法的话就使用@setter注解,get方法亦然,如果set和get方法都要的话就是用@data注解,
对应的也有@ToString方法,@EqualAndHashCode注解,见名知意。
二.动态更新数据库中的updateTime字段
通常我们创建一张数据库表的时候,都会加上createTime和updateTime两个字段,尽管你觉得这两个字段暂时用不上,但是这是一个好的习惯,而在创建的sql语句中,这两个字段的sql如下:
`create_time` timestamp not null default current_timestamp comment '创建时间',
`update_time` timestamp not null default current_timestamp on update current_timestamp comment '修改时间'
这两个字段都是时间类型,并且createTime设置了current_timestamp,即每一条数据加入来时这个字段都是以当前时间为数据记录到数据库,并且该字段的值不会因为更新修改而改变,而updateTime与createTime不同的就是设置了current_timestamp on update current_timestamp,这个设置以后的每一次更新修改都会影响这个字段的值,即为当前修改的时间。
所以在我们使用springboot的jpa时,当我们对数据进行更新操作的时候
@Test
public void update() {
ProductCategory productCategory = productCategoryDao.findOne(2);
productCategory.setCategoryType(10);
productCategoryDao.save(productCategory);
}
例如我们先查出这条数据对应的对象,然后再对这个对象进行setxxx,然后save你会发现数据库中的type是改变了,但是updateTime并没有改变,还是原来的值,所以说我们在数据库中设置了updateTime字段的自动修改的属性并没有用,因为我们把对象查出来了,我们只是修改了对象的type属性,并没有修改updateTime的值呀,好像也不对,不是在数据库中设置了current_timestamp on update current_timestamp这个设置了吗?其实在这里我们只需要在javabean对象上加上注解@DynamicUpdate就可以了,加上这个注解然后再在数据库中设置current_timestamp on update current_timestamp就能实现updateTime自动随我们修改这一条数据的任何一个字段而修改为当前时间了。
三 事务的运用@transactional
事务的运用可以帮我们轻松实现一些数据统一的问题,在springboot中,可以使用注解@transactional去实现事务。
例如我这里的创建订单的业务,先插入订单详情的商品数据 ,然后再计算订单总价格,最后生成总订单,扣库存,而对于这里的每一个步骤来讲,应该要封装成一个事务来防止其中的数据库操作出错,例如一旦在扣库存这里发现库存不足,就会发生回滚,之前插入更新删除的数据都会恢复原来的样子。
在@transactional注解中还有个propagation 属性,来描述事务的行为。默认是Propagation.REQUIRED。就是说当前不存在事务的话就创建一个新的事务,否则就加入这个事务。
https://blog.csdn.net/nextyu/article/details/78669997 这是在springboot中使用@transactional的用法
四.WebSocket
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。首先为什么要WebSocket?Http协议是无状态,无连接,单向的应用层协议,一旦连接断开之后,之后的连接都和前面的连接毫无关联了,这样就有一个弊端,就是服务端无法主动推送信息给客户端,如果要实时获取服务器的信息的话,可以使用轮询的方法,隔几秒就请求一次服务器,但是这样的话太过于浪费资源,对于手机移动端来说就更是浪费流量了,还有一种就是与服务器建立长连接,实现服务器的主动推送信息给客户端,而WebSocket就是为此而生的。
在springboot中去开发WebSocket通信,首先加入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
然后加入配置类,启用WebSocket的支持
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
创建WebSocket的监听类
@Component
@ServerEndpoint("/webSocket")
@Slf4j
public class WebSocket {
private Session session;
public static CopyOnWriteArraySet<WebSocket> webSocketCopyOnWriteArraySet = new CopyOnWriteArraySet<>();
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketCopyOnWriteArraySet.add(this);
log.error("【一个新的连接已建立】,连接总数为{}", webSocketCopyOnWriteArraySet.size());
}
@OnClose
public void onClose() {
webSocketCopyOnWriteArraySet.remove(this);
log.error("【一个连接已断开】,连接总数为{}", webSocketCopyOnWriteArraySet.size());
}
@OnMessage
public void onMessage(String message) {
log.error("收到客户端发来的信息,信息内容为{}", message);
}
public void sendMessage(String message) {
for (WebSocket webSocket : webSocketCopyOnWriteArraySet) {
try {
log.error("发送新的信息{},", message);
webSocket.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
在这个监听类中能监听到建立连接,断开连接,收发信息这些操作,在这里面有一个静态的集合用来保存每一个客户端与服务端建立连接的WebSocket的实例,连接成功之后会有一个session对象,该对象就是用来推送信息给连接的客户端的。
客户端中的js代码
每个方法的名字都对应着其意的操作。客户端收到信息会触发onmessage事件,在这里我们可以操作弹窗,打开铃声提醒等等。
五.面向切面AOP
AOP在平时写代码的时候用得比较少,spring的两个核心IOC和AOP,在项目中,比如权限的检验就可以用到AOP了,面向切面是把一些重复性的代码在横向地切入到我们运行中的代码中,而权限的检验基本上每个URL都需要,所以AOP能比较优雅地实现我们的需求。
下面先说下AOP里面的几个常用术语:
连接点(Joinpoint)
连接点是指增强程序执行的某个特定位置(要在哪个地方做增强操作),Spring仅支持方法的连接点,既仅能在方法调用前,方法调用后,方法抛出异常时等这些程序执行点进行织入增强。
切点(Pointcut)
切点是一组连接点的集合。即指点了一个范围来确定哪些连接点。
增强(Advice)
增强是织入到目标类连接点上的一段程序代码。表示要在连接点上做的操作。
切面(Aspect)
切面由切点和增强(引介)组成(可以包含多个切点和多个增强),它既包括了横切逻辑的定义,也包括了连接点的定义,SpringAOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的链接点中。
理解好AOP这几个术语的概念会对以后面向切面编程有较大的帮助.
下面来说一下在SpringBoot中使用AOP如何使用。
1.定义一个切面
@Aspect//定义一个切面
@Component
@Slf4j
public class SellerAuthorizeAspect {
}
2.定义切面
//定义切点,即后面的增强加在指定的切点中,切点是一组连接点的集合,即指定一个范围,
//这些范围内的连接点就是需要增强的地方
@Pointcut("execution(public * com.zyh.sell.controller.Seller*.*(..))"
+ "&& !execution(public * com.zyh.sell.controller.SellerUserController.*(..))")
public void verify() {
}
3.定义Advice
//增强的方法,即Advice
@Before("verify()")
public void doVerify() {
//查询cookie中的token
//得到request对象
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Cookie cookie = CookieUtil.get(request, Constant.CookieConstant.TOKEN);
if (cookie == null) {
log.error("【cookie校验失败】");
throw new SellerAuthorizeException();
}
//查询redis
String openid = stringRedisTemplate.opsForValue().get(String.format(Constant.RedisConstant.TOKEN_PREFIX, cookie.getValue()));
if (StringUtils.isEmpty(openid)){
log.error("【redis校验失败】");
throw new SellerAuthorizeException();
}
}
完整的一个切面代码:
@Aspect//定义一个切面
@Component
@Slf4j
public class SellerAuthorizeAspect {
@Autowired
private StringRedisTemplate stringRedisTemplate;
//定义切点,即后面的增强加在指定的切点中,切点是一组连接点的集合,即指定一个范围,
//这些范围内的连接点就是需要增强的地方
@Pointcut("execution(public * com.zyh.sell.controller.Seller*.*(..))"
+ "&& !execution(public * com.zyh.sell.controller.SellerUserController.*(..))")
public void verify() {
}
//增强的方法,即Advice
@Before("verify()")
public void doVerify() {
//查询cookie中的token
//得到request对象
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Cookie cookie = CookieUtil.get(request, Constant.CookieConstant.TOKEN);
if (cookie == null) {
log.error("【cookie校验失败】");
throw new SellerAuthorizeException();
}
//查询redis
String openid = stringRedisTemplate.opsForValue().get(String.format(Constant.RedisConstant.TOKEN_PREFIX, cookie.getValue()));
if (StringUtils.isEmpty(openid)){
log.error("【redis校验失败】");
throw new SellerAuthorizeException();
}
}
}
六.控制器增强器@ControllerAdvice
在spring3.2中加入了@ContollerAdvice这个注解,意为控制器增强器,@ControllerAdvice注解将作用在所有注解了@RequestMapping的控制器的方法上
上代码:
//控制器增强器
@ControllerAdvice
public class SellerExceptionHandler {
//当控制器发生指定的异常时就会触发指定的方法来增强控制器
@ExceptionHandler(value = SellerAuthorizeException.class)
public ModelAndView handleSellerAuthorizeException() {
return new ModelAndView("redirect:");
}
}
当controller抛出了SellerAuthorizeException时就会触发handleSellerAuthorizeException方法。