项目中的工具使用
knife4J
- 导包
<dependency><groupId>com.github.xiaoymingroupId><artifactId>knife4j-spring-boot-starterartifactId>dependency><dependency><groupId>com.github.xiaoymingroupId><artifactId>knife4j-springdoc-uiartifactId>dependency>
- 配置类
package com.imooc;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfig {@Beanpublic Docket defaultApi2() {Docket docket=new Docket(DocumentationType.SWAGGER_2).apiInfo(new ApiInfoBuilder()//.title("swagger-bootstrap-ui-demo RESTful APIs").description("慕红薯短视频实战接口文档").termsOfServiceUrl("http://www.xx.com/").contact(new Contact("lee", "http://www.imooc.com/", "abc@imooc.com")).version("1.0").build())//分组名称.groupName("2.X版本").select()//这里指定Controller扫描包路径.apis(RequestHandlerSelectors.basePackage("com.imooc.controller")).paths(PathSelectors.any()).build();return docket;}
}
腾讯云短信工具(一种读取properties配置文件的示例)
- 导入依赖
<!-- /> -->
<dependency><groupId>com.tencentcloudapigroupId><artifactId>tencentcloud-sdk-javaartifactId><version>3.1.270version>dependency>
- 创建properties配置文件,用于配置密码
# 从腾讯云中生成并且获得
tencent.cloud.secretId=A*************
tencent.cloud.secretKey=l****************
- 创建工具类读取配置
package com.imooc.utils;/*映射类,专门获取Tencetcloud.properties*/import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;@Component
@Data
/*以下两个注解,替代了之前的资源文件的加载代码*/
@PropertySource("classpath:tencentcloud.properties") //表示资源文件映射的是哪一个
@ConfigurationProperties(prefix = "tencent.cloud") //通过点操作的,把前缀加进来
public class TencentCloudProperties {private String secretId;private String secretKey;
}
- 使用工具类,将配置信息注入工具类中
package com.imooc.utils;import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class SMSUtils {@Autowiredprivate TencentCloudProperties tencentCloudProperties;public void sendSMS(String phone, String code) throws Exception {try {/* 必要步骤:* 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。* 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。* 你也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人,* 以免泄露密钥对危及你的财产安全。* CAM密匙查询获取: https://console.cloud.tencent.com/cam/capi*/Credential cred = new Credential(tencentCloudProperties.getSecretId(),tencentCloudProperties.getSecretKey());// 实例化一个http选项,可选的,没有特殊需求可以跳过HttpProfile httpProfile = new HttpProfile();// httpProfile.setReqMethod("POST"); // 默认使用POST/* SDK会自动指定域名。通常是不需要特地指定域名的,但是如果你访问的是金融区的服务* 则必须手动指定域名,例如sms的上海金融区域名: sms.ap-shanghai-fsi.tencentcloudapi.com */httpProfile.setEndpoint("sms.tencentcloudapi.com");// 实例化一个client选项ClientProfile clientProfile = new ClientProfile();clientProfile.setHttpProfile(httpProfile);// 实例化要请求产品的client对象,clientProfile是可选的SmsClient client = new SmsClient(cred, "ap-nanjing", clientProfile);// 实例化一个请求对象,每个接口都会对应一个request对象SendSmsRequest req = new SendSmsRequest();String[] phoneNumberSet1 = {"+86" + phone};//电话号码req.setPhoneNumberSet(phoneNumberSet1);req.setSmsSdkAppId("1*******8"); // 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppIdreq.setSignName("喜欢历史的工科生公众号"); // 签名req.setTemplateId("******"); // 模板id:必须填写已审核通过的模板 ID。模板ID可登录 [短信控制台] 查看/* 模板参数(自定义占位变量): 若无模板参数,则设置为空 */String[] templateParamSet1 = {code};req.setTemplateParamSet(templateParamSet1);// 返回的resp是一个SendSmsResponse的实例,与请求对象对应SendSmsResponse resp = client.SendSms(req);// 输出json格式的字符串回包
// System.out.println(SendSmsResponse.toJsonString(resp));} catch (TencentCloudSDKException e) {System.out.println(e.toString());}}// public static void main(String[] args) {
// try {
// new SMSUtils().sendSMS("17864264616", "7896");
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
}
Redis使用
- 导包
<dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-data-redisartifactId>dependency>
- 导入Redis工具类(封装了StringRedisTemplate)
- 配置yml文件
spring:redis:host: ***********port: 6379database: 0password: ******
项目中异常错误返回
如果项目中有要返回给前端的错误异常,可以通过自定义异常的方式,然后拦截异常并返回给前端
- 定义枚举类,用于存储常量,该常量定义了返回给前端的内容(ResponseStatusEnum),最后将这些枚举传入到一个优雅的返回类(GraceJSONResult)中。这也是前后端交互的一种处理。
- 定义异常,继承RunntimeException
package com.imooc.exceptions;
import com.imooc.grace.result.ResponseStatusEnum;/*** 自定义异常* 目的:统一处理异常信息* 便于解耦,拦截器、service与controller 异常错误的解耦,* 不会被service返回的类型而限制*//*定义一个异常类,然后利用枚举类输出异常的消息,拦截程序位置处只能返回true或者false表示是否放行如果拦截,我们需要给给前端返回相应的信息,所以采用抛出异常并捕获异常的方式,在捕获异常程序的位置处返回json数据*/
public class MyCustomException extends RuntimeException {private ResponseStatusEnum responseStatusEnum;public MyCustomException(ResponseStatusEnum responseStatusEnum) {super("异常状态码为:" + responseStatusEnum.status()+ ";具体异常信息为:" + responseStatusEnum.msg());this.responseStatusEnum = responseStatusEnum;}public ResponseStatusEnum getResponseStatusEnum() {return responseStatusEnum;}public void setResponseStatusEnum(ResponseStatusEnum responseStatusEnum) {this.responseStatusEnum = responseStatusEnum;}
}
- 定义异常拦截类
异常拦截类上添加@ControllerAdvice,并在类中的方法上添加@ExceptionHandler(异常.class)注解,用于捕获特定的异常
package com.imooc.exceptions;import com.imooc.grace.result.GraceJSONResult;import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;/*** 统一异常拦截处理* 可以针对异常的类型进行捕获,然后返回json信息到前端*/
@ControllerAdvice
public class GraceExceptionHandler {@ExceptionHandler(MyCustomException.class)@ResponseBodypublic GraceJSONResult returnMyException(MyCustomException e) {e.printStackTrace();return GraceJSONResult.exception(e.getResponseStatusEnum());}
}
对某个路由进行拦截
编写类实现andlerInterceptor,重写其中的三个拦截方法,再编写配置类实现WebMvcConfigurer,从写addInterceptors方法,并在该类中将andlerInterceptor的实现利用@Bean方式添加到容器中
- 编写类实现andlerInterceptor
@Slf4j
//可以使用日志 log.info(stu.toString());log.debug(stu.toString());log.warn(stu.toString());log.error(stu.toString());
//日志级别可以去yml文件中配置
public class PassportInterceptor extends BaseInfoProperties implements HandlerInterceptor{/*在访问controller之前请求,会被这个方法所拦截到*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {/*这里利用request获得用户IP*/String userIp = IPUtil.getRequestIp(request);// 得到是否存在的判断boolean keyIsExist = redis.keyIsExist(MOBILE_SMSCODE + ":" + userIp);if (keyIsExist) {GraceException.display(ResponseStatusEnum.SMS_NEED_WAIT_ERROR); //这里会抛出异常log.info("短信发送频率太大!");return false;}/*true:代表请求放行false:代表请求拦截*/return true;}/*在访问controller之后,渲染视图之前,会执行这个函数*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}/*整个请求都结束了,视图渲染完毕之后,会进入到这个方法*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}
- 编写配置类注册拦截器
package com.imooc;import com.imooc.interceptor.PassportInterceptor;
import com.imooc.interceptor.UserTokenInterceptor;
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 InterceptorConfig implements WebMvcConfigurer{/*在spring容器中生成一个PassportInterceptor对象*/@Beanpublic PassportInterceptor passportInterceptor() {return new PassportInterceptor();}/*注册拦截器将PassportInterceptor对象注册到registry中*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(passportInterceptor()).addPathPatterns("/passport/getSMSCode");}
}
前端输入参数的验证
导入spring-boot-starter-validation验证框架;建立业务对象BO,用于接收前端传来的数据对象,标记处理验证位置;编写接收接口,并处理验证异常
- 导入spring-boot-starter-validation验证框架
<dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-validationartifactId>dependency>
- 建立业务对象BO,标记处理验证位置
package com.imooc.bo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class RegistLoginBO {@NotBlank(message = "手机号不能为空")@Length(min = 11, max=11, message = "手机号长度不正确") //框架中的注解private String mobile;@NotBlank(message = "验证码不能为空")private String smsCode;}
- 编写接收接口,并处理验证异常,因为直接处理得到的错误结果,那么会对代码造成侵入,所以用异常拦截的方式处理
@GetMapping("login")public Object login(@Valid @RequestBody RegistLoginBO registLoginBO,HttpServletRequest request) throws Exception {}
/*** 统一异常拦截处理* 可以针对异常的类型进行捕获,然后返回json信息到前端*/
@ControllerAdvice
public class GraceExceptionHandler {@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseBodypublic GraceJSONResult returnMethodArgumentNotValid(MethodArgumentNotValidException e) {BindingResult result = e.getBindingResult();Map<String, String> map = getErrors(result);return GraceJSONResult.errorMap(map);}public Map<String, String> getErrors(BindingResult result) {Map<String, String> map = new HashMap<>();List<FieldError> errorList = result.getFieldErrors();for (FieldError ff : errorList) {// 错误所对应的属性字段名String field = ff.getField();// 错误的信息String msg = ff.getDefaultMessage();map.put(field, msg);}return map;}
}
MINIO使用
- 导包
<dependency><groupId>io.miniogroupId><artifactId>minioartifactId>dependency>
- 引入工具类:工具类中有操作的API以及创建一个客户端连接
- 配置yml文件中的minio相关信息
# MinIO 配置
minio:endpoint: http://192.168.137.234:9000 # MinIO服务地址 API通信地址fileHost: http://192.168.137.234:9000 # 文件地址host 新版本会多一个bucketName: ****** # 存储桶bucket名称accessKey: ***** # 用户名 视频里面是rootsecretKey: ********** # 密码imgSize: 1024 # 图片大小限制,单位:mfileSize: 1024 # 文件大小限制,单位:m
- 编写minio配置类
package com.imooc;import com.imooc.utils.MinIOUtils;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*这些value的值就是映射yml中的配置*/
@Configuration
@Data
public class MinIOConfig {@Value("${minio.endpoint}")private String endpoint;@Value("${minio.fileHost}")private String fileHost;@Value("${minio.bucketName}")private String bucketName;@Value("${minio.accessKey}")private String accessKey;@Value("${minio.secretKey}")private String secretKey;@Value("${minio.imgSize}")private Integer imgSize;@Value("${minio.fileSize}")private Integer fileSize;@Beanpublic MinIOUtils creatMinioClient() {/*在容器中就会包含我们的工具类。生成工具类的实例的时候就会有创建minioClient实例了*/return new MinIOUtils(endpoint, bucketName, accessKey, secretKey, imgSize, fileSize);}
}
- 测试
package com.imooc.controller;import com.imooc.MinIOConfig;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.model.Stu;
import com.imooc.utils.MinIOUtils;
import com.imooc.utils.SMSUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;@Slf4j
@Api(tags = "FileController 文件上传测试的接口")
@RestController
public class FileController {@Autowiredprivate MinIOConfig minIOConfig;/*文件上传要采用Post*/@PostMapping("upload")public GraceJSONResult upload(MultipartFile file) throws Exception {String fileName = file.getOriginalFilename();/*将前端传来的文件上传到minio中*/MinIOUtils.uploadFile(minIOConfig.getBucketName(),fileName,file.getInputStream());/*获得miniode分享连接(public模式的)*/String imgUrl = minIOConfig.getFileHost()+ "/"+ minIOConfig.getBucketName()+ "/"+ fileName;return GraceJSONResult.ok(imgUrl);}
}
添加Mybatis的分页插件
- 导包
<dependency><groupId>com.github.pagehelpergroupId><artifactId>pagehelper-spring-boot-starterartifactId>dependency>
- 配置yml
# 分页插件助手的配置
pagehelper:helper-dialect: MYSQLsupport-methods-arguments: true
- 拦截Service层代码
@Overridepublic PagedGridResult getIndexVlogList(String search,Integer page,Integer pageSize) {//添加分页PageHelper .startPage(page, pageSize); //拦截原理在sql上添加分页语句Map<String, Object> map = new HashMap<>();if (StringUtils.isNotBlank(search)) {map.put("search", search);}List<IndexVlogVO> list = vlogMapperCustom.getIndexVlogList(map);//list的结果就是分页后的结果return setterPagedGrid(list, page); //根据查询的结果对对其进行封装}public PagedGridResult setterPagedGrid(List<?> list,Integer page) {//插件中根据结果获得一些信息的对象PageInfo<? > pageList = new PageInfo<>(list);//PagedGridResult根据前端的格式建立的PagedGridResult gridResult = new PagedGridResult();gridResult.setRows(list);gridResult.setPage(page);gridResult.setRecords(pageList.getTotal());gridResult.setTotal(pageList.getPages());return gridResult;}package com.imooc.utils;import java.util.List;/*** * @Title: PagedGridResult.java* @Package com.imooc.utils* @Description: 用来返回分页Grid的数据格式* Copyright: Copyright (c) 2021*/
public class PagedGridResult {private int page; // 当前页数private long total; // 总页数private long records; // 总记录数private List<?> rows; // 每行显示的内容public int getPage() {return page;}public void setPage(int page) {this.page = page;}public long getTotal() {return total;}public void setTotal(long total) {this.total = total;}public void setTotal(int total) {this.total = total;}public long getRecords() {return records;}public void setRecords(long records) {this.records = records;}public List<?> getRows() {return rows;}public void setRows(List<?> rows) {this.rows = rows;}
}
MongoDB使用
- 导包
<dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-data-mongodbartifactId>dependency>
- 配置yml文件
spring:data:mongodb:uri: mongodb://root:root@192.168.137.234:27017database: imooc-red-book
- 和数据库一样建立mo(po)
package com.imooc.mo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;import java.util.Date;
import java.util.Map;@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
/*message会映射到数据库里面的,对应表(Collection)的名字*/
@Document("message")
public class MessageMO {/*mongodb自己会生成,不用进行赋值*/@Idprivate String id; // 消息主键id@Field("fromUserId")private String fromUserId; // 消息来自的用户id@Field("fromNickname")private String fromNickname; // 消息来自的用户昵称@Field("fromFace")private String fromFace; // 消息来自的用户头像@Field("toUserId")private String toUserId; // 消息发送到某对象的用户id@Field("msgType")private Integer msgType; // 消息类型 枚举@Field("msgContent")private Map msgContent; // 消息内容@Field("createTime")private Date createTime; // 消息创建时间
}
- mapper层,和通用mapper类似
package com.imooc.respository;import com.imooc.mo.MessageMO;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;import java.util.List;
/*可以作为通用mapper*/
@Repository
public interface MessageRepository extends MongoRepository<MessageMO, String> {// 通过实现Repository,自定义条件查询,下面的字段和mo的属性对应List<MessageMO> findAllByToUserIdEqualsOrderByCreateTimeDesc(String toUserId,Pageable pageable);
// void deleteAllByFromUserIdAndToUserIdAndMsgType();
}
- Service层
package com.imooc.service;import com.imooc.bo.VlogBO;
import com.imooc.mo.MessageMO;import javax.validation.constraints.Max;
import java.util.List;
import java.util.Map;public interface MsgService {/*** 创建消息*/public void createMsg(String fromUserId,String toUserId,Integer type,Map msgContent);/*** 查询消息列表*/public List<MessageMO> queryList(String toUserId,Integer page,Integer pageSize);}
package com.imooc.service.impl;import com.imooc.base.BaseInfoProperties;
import com.imooc.enums.MessageEnum;
import com.imooc.mo.MessageMO;
import com.imooc.pojo.Users;
import com.imooc.respository.MessageRepository;
import com.imooc.service.MsgService;
import com.imooc.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@Service
public class MsgServiceImpl extends BaseInfoProperties implements MsgService {@Autowiredprivate MessageRepository messageRepository;@Autowiredprivate UserService userService;@Overridepublic void createMsg(String fromUserId,String toUserId,Integer type,Map msgContent) {/*查询发消息的谁*/Users fromUser = userService.getUser(fromUserId);MessageMO messageMO = new MessageMO();messageMO.setFromUserId(fromUserId);messageMO.setFromNickname(fromUser.getNickname());messageMO.setFromFace(fromUser.getFace());messageMO.setToUserId(toUserId);messageMO.setMsgType(type);if (msgContent != null) {messageMO.setMsgContent(msgContent);}messageMO.setCreateTime(new Date());messageRepository.save(messageMO);}@Overridepublic List<MessageMO> queryList(String toUserId,Integer page,Integer pageSize) {/*按照查询的排序进行分页*/Pageable pageable = PageRequest.of(page,pageSize,Sort.Direction.DESC,"createTime");/*这个函数findAllByToUserIdEqualsOrderByCreateTimeDesc是可以根据MO中的字段生成的*/List<MessageMO> list = messageRepository.findAllByToUserIdEqualsOrderByCreateTimeDesc(toUserId,pageable);/*要判断是否是相互关注*/for (MessageMO msg : list) {// 如果类型是关注消息,则需要查询我之前有没有关注过他,用于在前端标记“互粉”“互关”if (msg.getMsgType() != null && msg.getMsgType() == MessageEnum.FOLLOW_YOU.type) {Map map = msg.getMsgContent();if (map == null) {map = new HashMap();}String relationship = redis.get(REDIS_FANS_AND_VLOGGER_RELATIONSHIP + ":" + msg.getToUserId() + ":" + msg.getFromUserId());if (StringUtils.isNotBlank(relationship) && relationship.equalsIgnoreCase("1")) {map.put("isFriend", true);} else {map.put("isFriend", false);}msg.setMsgContent(map);}}return list;}}
- 调用
消息入库:关注的时候,调用msgService.createMsg(myId, vlogerId, MessageEnum.FOLLOW_YOU.type, null);
public void doFollow(String myId, String vlogerId) {String fid = sid.nextShort();Fans fans = new Fans();fans.setId(fid);fans.setFanId(myId);fans.setVlogerId(vlogerId);// 判断对方是否关注我,如果关注我,那么双方都要互为朋友关系Fans vloger = queryFansRelationship(vlogerId, myId);if (vloger != null) {fans.setIsFanFriendOfMine(YesOrNo.YES.type);vloger.setIsFanFriendOfMine(YesOrNo.YES.type);fansMapper.updateByPrimaryKeySelective(vloger);} else {fans.setIsFanFriendOfMine(YesOrNo.NO.type);}fansMapper.insert(fans);// 系统消息:关注msgService.createMsg(myId, vlogerId, MessageEnum.FOLLOW_YOU.type, null);}
@Transactional@Overridepublic void userLikeVlog(String userId, String vlogId) {/*重要数据的一个部署*/String rid = sid.nextShort();MyLikedVlog likedVlog = new MyLikedVlog();likedVlog.setId(rid);likedVlog.setVlogId(vlogId);likedVlog.setUserId(userId);myLikedVlogMapper.insert(likedVlog);/*非重要消息,把点赞的消息入库,如果说这里出现错误,因为有事务,所以会将重要事务回滚,所以要一步执行非重要数据*/Vlog vlog = this.getVlog(vlogId);Map msgContent = new HashMap();/*放入的键要和前端一致,当前用户点赞放入到mongodb然后查询的时候从mongodb中查询前端根据msgcontent中的键值对进行渲染,所以键要和前端的对应*/msgContent.put("vlogId",vlogId);msgContent.put("vlogCover",vlog.getCover());msgService.createMsg(userId,vlog.getVlogerId(),MessageEnum.LIKE_VLOG.type,msgContent);}
- controller层 查询消息
package com.imooc.controller;import com.imooc.base.BaseInfoProperties;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.mo.MessageMO;
import com.imooc.model.Stu;
import com.imooc.service.MsgService;
import com.imooc.utils.SMSUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@Slf4j
@Api(tags = "MsgController 消息功能模块的接口")
@RequestMapping("msg")
@RestController
public class MsgController extends BaseInfoProperties {@Autowiredprivate MsgService msgService;@GetMapping("list")public GraceJSONResult list(@RequestParam String userId,@RequestParam Integer page,@RequestParam Integer pageSize) {// mongodb 从0分页,区别于数据库if (page == null) {page = COMMON_START_PAGE_ZERO;}if (pageSize == null) {pageSize = COMMON_PAGE_SIZE;}List<MessageMO> list = msgService.queryList(userId, page, pageSize);return GraceJSONResult.ok(list);}
}
RabbitMQ的使用
- 导包
<dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-amqpartifactId>dependency>
- 配置yml文件
rabbitmq:host: 192.168.1.204port: 5672username: adminpassword: adminvirtual-host: imooc-red-book
- 创建交换机和队列
package com.imooc;
//
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMQConfig {// /**
// * 根据模型编写代码:
// * 1. 定义交换机
// * 2. 定义队列
// * 3. 创建交换机
// * 4. 创建队列
// * 5. 队列和交换机的绑定
// */public static final String EXCHANGE_MSG = "exchange_msg";public static final String QUEUE_SYS_MSG = "queue_sys_msg";@Bean(EXCHANGE_MSG)public Exchange exchange() {return ExchangeBuilder // 构建交换机.topicExchange(EXCHANGE_MSG) // 使用topic类型,参考:https://www.rabbitmq.com/getstarted.html.durable(true) // 设置持久化,重启mq后依然存在.build();}@Bean(QUEUE_SYS_MSG)public Queue queue() {return new Queue(QUEUE_SYS_MSG);}@Beanpublic Binding binding(@Qualifier(EXCHANGE_MSG) Exchange exchange,@Qualifier(QUEUE_SYS_MSG) Queue queue) {return BindingBuilder.bind(queue).to(exchange).with("sys.msg.*") // 定义路由规则(requestMapping).noargs();// FIXME: * 和 # 分别代表什么意思?}}
- 构建生产者发送消息
@Autowiredpublic RabbitTemplate rabbitTemplate;@GetMapping("produce")public Object produce() throws Exception {rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_MSG,"sys.msg.send", //根据路由规则写路由"我发了一个消息~~");/*** 路由规则* route-key* display.* display.a.b* display.public.msg* display.a.b.c* * 代表一个占位符** display.#* display.a.b* display.a.b.c.d* display.public.msg* display.delete.msg.do* # 代表多个占位符**/return GraceJSONResult.ok();}@GetMapping("produce2")public Object produce2() throws Exception {rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_MSG,"sys.msg.delete","我删除了一个消息~~");return GraceJSONResult.ok();}
- 消费者接收消息,处理业务
package com.imooc;import com.imooc.base.RabbitMQConfig;
import com.imooc.enums.MessageEnum;
import com.imooc.exceptions.GraceException;
import com.imooc.grace.result.ResponseStatusEnum;
import com.imooc.mo.MessageMO;
import com.imooc.service.MsgService;
import com.imooc.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Slf4j
@Component
public class RabbitMQConsumer {@Autowiredprivate MsgService msgService;@RabbitListener(queues = {RabbitMQConfig.QUEUE_SYS_MSG})public void watchQueue(String payload, Message message) {//payload 消息,message 具体的消息,从这里获得路由key//路由规则用* 号代替,但是生产者可以在占位符的地方写很多个路由。在消费者这里就可解析生产者发送的不同类型的路由了。log.info(payload);String routingKey = message.getMessageProperties().getReceivedRoutingKey();log.info(routingKey);}}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
