对象存储OSS
开发文件上传接口,需要使用阿里云OSS服务
-
首先需要购买一个OSS存储服务(可以去网上参考购买教程),并进行配置
-
然后再配置文件中加入下面属性
endpoint:你购买服务的地区 这两个为AccessKey,在登录阿里云账户,鼠标移动到头像上面既可以看到,获取下载即可 access-key-id: access-key-secret: bucket-name:你所创建的一个bucket名称,类似与保存文件的文件夹
3. 需要在设置配置类加载配置文件
aliOssProperties.getAccessKeyId()调用aliOssProperties类读取对应的数据
/**
* 配置类 , 用于创建AliOssUtil对象
*/
@Configuration
@Slf4j
public class OssConfiguration {
//添加bean注解当项目启动就会被调用
@Bean
@ConditionalOnMissingBean
public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties){
log.info("开始创建阿里云文件上传工具类对象:{}" , aliOssProperties);
return new AliOssUtil(aliOssProperties.getEndpoint(),
aliOssProperties.getAccessKeyId(),
aliOssProperties.getAccessKeySecret(),
aliOssProperties.getBucketName());
}
}
工具类AliOssUtil
@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
/**
* 文件上传
*
* @param bytes
* @param objectName
* @return
*/
public String upload(byte[] bytes, String objectName) {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
// 创建PutObject请求。
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
//文件访问路径规则 https://BucketName.Endpoint/ObjectName
StringBuilder stringBuilder = new StringBuilder("https://");
stringBuilder
.append(bucketName)
.append(".")
.append(endpoint)
.append("/")
.append(objectName);
log.info("文件上传到:{}", stringBuilder.toString());
return stringBuilder.toString();
}
}
- 开发通用上传接口
/**
* 文件上传
*
* @param file 参数名需要跟前端提交的参数名保持一致
* @return
*/
@PostMapping("/upload")
@ApiOperation("文件上传")
public Result<String> upload(MultipartFile file) {
// 需要注解slf4j
log.info("文件上传:{}", file);
try {
// 原始文件名
String originalFilename = file.getOriginalFilename();
// 截取原始文件名后缀
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
// 构造新文件名称
String objectName = UUID.randomUUID().toString() + extension;
//
String filePath = aliOssUtil.upload(file.getBytes(), objectName);
return Result.success(filePath);
} catch (IOException e) {
log.error("文件上上传失败:{}",e);
}
return Result.error(MessageConstant.UPLOAD_FAILED);
}
}
Spring Data Redis
使用步骤:
- 导入Spring Data Redis 的maven坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 配置Redis数据源
redis:
host: ${sky.redis.host}
port: ${sky.redis.port}
password: ${sky.redis.password}
database: ${sky.redis.database}
sky:
redis:
host: localhost
port: 6379
password: 123456
database: 10
- 编写配置类,创建RedisTemplate对象
@Configuration
@Slf4j
public class RedisConfiguration {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
log.info("开始创建redis模版对象...");
RedisTemplate redisTemplate = new RedisTemplate();
// 设置redis连接工厂对象 引入的坐标会创建
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 设置redis key的序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}
- 通过RedisTemplate对象操作Redis
@Autowired
private RedisTemplate redisTemplate
Apache POI
导入坐标
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
读取项目提供的模版文件,并查询数据写入导出:
@Override
public void exportBusinessDate(HttpServletResponse response) {
//1. 查询数据库 ,获取营业数据
LocalDate dateBegin = LocalDate.now().minusDays(30);
LocalDate dateEnd = LocalDate.now().minusDays(1);
BusinessDataVO businessDataVO = workspaceService.getBusinessData(LocalDateTime.of(dateBegin, LocalTime.MIN), LocalDateTime.of(dateEnd, LocalTime.MAX));
//2. 通过POI将数据写入Excel文件中 获得类对象 获得类加载器 在类路径下读取资源 返回一个输入流对象
InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
//基于模板文件创建一个新的Excel文件
try {
XSSFWorkbook excel = new XSSFWorkbook(in);
//获取表格文件的Sheet页
XSSFSheet sheet = excel.getSheet("sheet1");
//填充数据--时间
sheet.getRow(1).getCell(1).setCellValue("时间" + dateBegin + "至" + dateEnd);
//获得第4行
XSSFRow row = sheet.getRow(3);
row.getCell(2).setCellValue(businessDataVO.getTurnover());
row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());
row.getCell(6).setCellValue(businessDataVO.getNewUsers());
//获得第5行
row = sheet.getRow(4);
row.getCell(2).setCellValue(businessDataVO.getValidOrderCount());
row.getCell(4).setCellValue(businessDataVO.getUnitPrice());
//填充明细数据
for (int i = 0; i < 30; i++) {
LocalDate date = dateBegin.plusDays(i);
//查询某一天的营业数据
BusinessDataVO businessData = workspaceService.getBusinessData(LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX));
//获得某一行
row = sheet.getRow(7 + i);
row.getCell(1).setCellValue(date.toString());
row.getCell(2).setCellValue(businessData.getTurnover());
row.getCell(3).setCellValue(businessData.getValidOrderCount());
row.getCell(4).setCellValue(businessData.getOrderCompletionRate());
row.getCell(5).setCellValue(businessData.getUnitPrice());
row.getCell(6).setCellValue(businessData.getNewUsers());
}
//3. 通过输出流将Excel文件下载到客户端浏览器
ServletOutputStream out = response.getOutputStream();
excel.write(out);
//关闭资源
out.close();
excel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Spring Task
使用步骤:
-
导入maven坐标 spring-context(已存在)
-
启动类添加注解 @EnableScheduling 开启任务调度
-
自定义定时任务类
通过定时任务每分钟检查一次是否存在支付超时订单(下单后超过15分钟仍未支付则判定为支付超时订单) 如果存在则修改订单状态为“已取消”通过定时任务每天凌晨1点检查一次是否存在“派送中”的订单,如果存在则修改订单状态为“已完成”
@Scheduled(cron = "0 * * * * ?")//每分钟触发一次
@Scheduled(cron = "0 0 1 * * ?")//每天凌晨一点触发
@Component
@Slf4j
public class OrderTask {
@Autowired
private OrderMapper orderMapper;
/**
* 处理超时订单的方法
*/
@Scheduled(cron = "0 * * * * ?")//每分钟触发一次
// @Scheduled(cron = "1/5 * * * * ?")
public void processTimeoutOrder() {
log.info("定时处理超时订单:{} ", LocalDateTime.now());
LocalDateTime time = LocalDateTime.now().plusMinutes(-15);
//select * from orders where status = ? and order_time(当前时间 - 15)
List<Orders> ordersList = orderMapper.getByStatusAndOrderTimeLT(Orders.PENDING_PAYMENT, time);
if (ordersList != null && ordersList.size() > 0) {
for (Orders orders : ordersList) {
orders.setStatus(Orders.CANCELLED);
orders.setCancelReason("订单超时,自动取消");
orders.setCancelTime(LocalDateTime.now());
orderMapper.update(orders);
}
}
}
/**
* 处理一直处于派送中状态的订单
*/
@Scheduled(cron = "0 0 1 * * ?")//每天凌晨一点触发
// @Scheduled(cron = "0/5 * * * * ?")
public void processDeliveryOrder() {
log.info("处理一直处于派送中状态的订单:{}", LocalDateTime.now());
LocalDateTime time = LocalDateTime.now().plusMinutes(-60);
//查询上一个工作日派送中的订单
List<Orders> ordersList = orderMapper.getByStatusAndOrderTimeLT(Orders.DELIVERY_IN_PROGRESS, time);
if (ordersList != null && ordersList.size() > 0) {
for (Orders orders : ordersList) {
orders.setStatus(Orders.COMPLETED);
orderMapper.update(orders);
}
}
}
}
WebSocket
WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接, 并进行双向数据传输
实现步骤:
- 直接使用websocket.html页面作为WebSocket客户端
- 导入WebSocket的maven坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
- 导入WebSocket服务端组件WebSocketServer,用于和客户端通信
/**
* WebSocket服务
*/
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {
//存放会话对象
private static Map<String, Session> sessionMap = new HashMap();
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid) {
System.out.println("客户端:" + sid + "建立连接");
sessionMap.put(sid, session);
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, @PathParam("sid") String sid) {
System.out.println("收到来自客户端:" + sid + "的信息:" + message);
}
/**
* 连接关闭调用的方法
*
* @param sid
*/
@OnClose
public void onClose(@PathParam("sid") String sid) {
System.out.println("连接断开:" + sid);
sessionMap.remove(sid);
}
/**
* 群发
*
* @param message
*/
public void sendToAllClient(String message) {
Collection<Session> sessions = sessionMap.values();
for (Session session : sessions) {
try {
//服务器向客户端发送消息
session.getBasicRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
- 导入配置类WebSocketConfiguration,注册WebSocket的服务端组件
/**
* WebSocket配置类,用于注册WebSocket的Bean
*/
@Configuration
public class WebSocketConfiguration {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
- 导入定时任务类WebSocketTask,定时向客户端推送数据
@Component
public class WebSocketTask {
@Autowired
private WebSocketServer webSocketServer;
/**
* 通过WebSocket每隔5秒向客户端发送消息
*/
@Scheduled(cron = "0/5 * * * * ?")
public void sendMessageToClient() {
webSocketServer.sendToAllClient("这是来自服务端的消息:" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));
}
}