程序员蜗牛
1 year ago
9 changed files with 383 additions and 0 deletions
@ -0,0 +1,77 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<parent> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-parent</artifactId> |
|||
<version>2.7.4</version> |
|||
<relativePath/> <!-- lookup parent from repository --> |
|||
</parent> |
|||
<groupId>com.example</groupId> |
|||
<artifactId>demo-request-scope</artifactId> |
|||
<version>0.0.1-SNAPSHOT</version> |
|||
<name>demo-request-scope</name> |
|||
<description>Demo project for Spring Boot</description> |
|||
<properties> |
|||
<java.version>8</java.version> |
|||
</properties> |
|||
|
|||
|
|||
<dependencies> |
|||
|
|||
<dependency> |
|||
<groupId>com.google.guava</groupId> |
|||
<artifactId>guava</artifactId> |
|||
<version>30.1-jre</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-aop</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-data-redis</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-web</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>cn.hutool</groupId> |
|||
<artifactId>hutool-all</artifactId> |
|||
<version>5.8.16</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.alibaba</groupId> |
|||
<artifactId>easyexcel</artifactId> |
|||
<version>3.3.2</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-test</artifactId> |
|||
<scope>test</scope> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.projectlombok</groupId> |
|||
<artifactId>lombok</artifactId> |
|||
<optional>true</optional> |
|||
</dependency> |
|||
</dependencies> |
|||
|
|||
<build> |
|||
<plugins> |
|||
<plugin> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-maven-plugin</artifactId> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
|
|||
</project> |
@ -0,0 +1,14 @@ |
|||
package com.example.demo; |
|||
|
|||
import org.springframework.boot.SpringApplication; |
|||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
|||
|
|||
|
|||
@SpringBootApplication |
|||
public class DemoRequestScopeApplication { |
|||
|
|||
public static void main(String[] args) { |
|||
SpringApplication.run(DemoRequestScopeApplication.class, args); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,30 @@ |
|||
package com.example.demo.config; |
|||
|
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
|
|||
import java.util.concurrent.ArrayBlockingQueue; |
|||
import java.util.concurrent.ThreadPoolExecutor; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
@Configuration |
|||
public class ThreadPoolConfig { |
|||
|
|||
private static final int corePoolSize = 10; // 核心线程数
|
|||
private static final int maximumPoolSize = 20; // 最大线程数
|
|||
private static final long keepAliveTime = 60L; // 空闲线程存活时间
|
|||
private static final TimeUnit TIME_UNIT = TimeUnit.SECONDS; |
|||
|
|||
@Bean |
|||
public ThreadPoolExecutor getThreadPoolExecutor() { |
|||
return new ThreadPoolExecutor( |
|||
corePoolSize, |
|||
maximumPoolSize, |
|||
keepAliveTime, |
|||
TIME_UNIT, |
|||
new ArrayBlockingQueue<>(2000), |
|||
new ThreadPoolExecutor.AbortPolicy() |
|||
); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,93 @@ |
|||
package com.example.demo.export; |
|||
|
|||
|
|||
|
|||
import cn.hutool.core.bean.BeanUtil; |
|||
import cn.hutool.core.util.PageUtil; |
|||
import com.alibaba.excel.EasyExcel; |
|||
import com.alibaba.excel.ExcelWriter; |
|||
import com.alibaba.excel.write.metadata.WriteSheet; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
import java.net.URLEncoder; |
|||
import java.util.List; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractExport<T, K> { |
|||
|
|||
|
|||
public abstract void export(ExportUser sysUser) throws InterruptedException; |
|||
|
|||
/** |
|||
* 导出 |
|||
* @param response 输出流 |
|||
* @param pageSize 每页大小 |
|||
* @param t 导出条件 |
|||
* @param k Excel内容实体类 |
|||
* @param fileName 文件名称 |
|||
*/ |
|||
public void export(HttpServletResponse response, int pageSize, T t, Class<K> k, String fileName) throws Exception { |
|||
ExcelWriter writer = null; |
|||
try { |
|||
writer = getExcelWriter(response, fileName); |
|||
//查询导出总条数
|
|||
int total = this.countExport(t); |
|||
//页数
|
|||
int loopCount = PageUtil.totalPage(total, pageSize); |
|||
BeanUtil.setProperty(t, "pageSize", pageSize); |
|||
for (int i = 0; i < loopCount; i++) { |
|||
//开始页
|
|||
BeanUtil.setProperty(t, "pageNum", PageUtil.getStart(i + 1, pageSize)); |
|||
//获取Excel导出信息
|
|||
List<K> kList = this.getExportDetail(t); |
|||
WriteSheet writeSheet = EasyExcel.writerSheet(fileName).head(k).build(); |
|||
writer.write(kList, writeSheet); |
|||
} |
|||
} catch (Exception e) { |
|||
String msg = "导出" + fileName + "异常"; |
|||
log.error(msg, e); |
|||
throw new Exception(msg + e); |
|||
} finally { |
|||
if (writer != null) { |
|||
writer.finish(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public ExcelWriter getExcelWriter(HttpServletResponse response, String fileName) throws IOException { |
|||
response.setContentType("application/vnd.ms-excel"); |
|||
response.setCharacterEncoding("utf-8"); |
|||
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
|
|||
String fileNameUtf = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20"); |
|||
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileNameUtf + ".xlsx"); |
|||
return EasyExcel.write(response.getOutputStream()).build(); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* (模版导出) |
|||
* |
|||
* @param t |
|||
* @param fileName |
|||
* @param response |
|||
*/ |
|||
public abstract void complexFillWithTable(T t, String fileName, HttpServletResponse response); |
|||
|
|||
/** |
|||
* 查询导出总条数 |
|||
* |
|||
* @param t |
|||
* @return |
|||
*/ |
|||
public abstract int countExport(T t); |
|||
|
|||
/** |
|||
* 查询导出数据 |
|||
* |
|||
* @param t |
|||
* @return |
|||
*/ |
|||
public abstract List<K> getExportDetail(T t); |
|||
} |
@ -0,0 +1,40 @@ |
|||
package com.example.demo.export; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.util.concurrent.ThreadPoolExecutor; |
|||
|
|||
@RestController |
|||
@RequestMapping("/export") |
|||
@Slf4j |
|||
public class ExportController { |
|||
|
|||
@Autowired |
|||
private ExportImpl export; |
|||
|
|||
@Autowired |
|||
private ThreadPoolExecutor threadPoolExecutor; |
|||
|
|||
/** |
|||
* 实现一个排队导出功能 |
|||
*/ |
|||
@PostMapping("/exportFile") |
|||
public void exportFile() { |
|||
log.info("提交线程池任务"); |
|||
threadPoolExecutor.execute(() -> { |
|||
ExportUser sysUser = new ExportUser(); |
|||
sysUser.setUserName(Thread.currentThread().getName()); |
|||
try { |
|||
export.export(sysUser); |
|||
} catch (InterruptedException e) { |
|||
throw new RuntimeException(e); |
|||
} |
|||
} |
|||
); |
|||
log.info("提交线程池任务结束"); |
|||
} |
|||
} |
@ -0,0 +1,58 @@ |
|||
package com.example.demo.export; |
|||
|
|||
import com.alibaba.excel.ExcelWriter; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
import java.util.LinkedList; |
|||
import java.util.List; |
|||
|
|||
@Service |
|||
@Slf4j |
|||
public class ExportImpl extends AbstractExport { |
|||
|
|||
@Autowired |
|||
private ExportQueue exportQueue; |
|||
|
|||
@Override |
|||
public void export(ExportUser sysUser) throws InterruptedException { |
|||
//导出
|
|||
log.info("导出文件方法执行~~~~~~~~~"); |
|||
LinkedList<ExportUser> queue = exportQueue.add(sysUser); |
|||
//可以考虑把队列进行持久化
|
|||
log.info("导出队列:" + queue); |
|||
//export(response,pageSize,t,k,fileName);
|
|||
//导出成功后移除当前导出用户
|
|||
ExportUser nextSysUser = exportQueue.getNextSysUser(); |
|||
log.info("移除后获取下一个排队的用户: " + nextSysUser.getUserName()); |
|||
} |
|||
|
|||
@Override |
|||
public void export(HttpServletResponse response, int pageSize, Object o, Class k, String fileName) throws Exception { |
|||
super.export(response, pageSize, o, k, fileName); |
|||
} |
|||
|
|||
@Override |
|||
public ExcelWriter getExcelWriter(HttpServletResponse response, String fileName) throws IOException { |
|||
return super.getExcelWriter(response, fileName); |
|||
} |
|||
|
|||
@Override |
|||
public void complexFillWithTable(Object o, String fileName, HttpServletResponse response) { |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public int countExport(Object o) { |
|||
return 0; |
|||
} |
|||
|
|||
@Override |
|||
public List getExportDetail(Object o) { |
|||
return null; |
|||
} |
|||
} |
|||
|
@ -0,0 +1,60 @@ |
|||
package com.example.demo.export; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.util.LinkedList; |
|||
|
|||
@Slf4j |
|||
@Component |
|||
public class ExportQueue { |
|||
|
|||
|
|||
private final int MAX_CAPACITY = 10; // 队列最大容量
|
|||
private LinkedList<ExportUser> queue; // 用户队列 或者阻塞队列 或者 直接消息队列
|
|||
|
|||
public ExportQueue(LinkedList<ExportUser> queue) { |
|||
this.queue = new LinkedList<>(); |
|||
} |
|||
|
|||
/** |
|||
* 排队队列添加 |
|||
* |
|||
* @param sysUser |
|||
*/ |
|||
public synchronized LinkedList<ExportUser> add(ExportUser sysUser) { |
|||
while (queue.size() >= MAX_CAPACITY) { |
|||
try { |
|||
log.info("当前排队人已满,请等待"); |
|||
wait(); |
|||
} catch (InterruptedException e) { |
|||
e.getMessage(); |
|||
} |
|||
} |
|||
queue.add(sysUser); |
|||
log.info("目前导出队列排队人数:" + queue.size()); |
|||
notifyAll(); |
|||
return queue; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取排队队列下一个人 |
|||
* |
|||
* @return |
|||
*/ |
|||
public synchronized ExportUser getNextSysUser() { |
|||
while (queue.isEmpty()) { |
|||
try { |
|||
wait(); |
|||
} catch (InterruptedException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
ExportUser sysUser = queue.remove(); |
|||
notifyAll(); //唤醒
|
|||
return sysUser; |
|||
} |
|||
} |
|||
|
|||
|
@ -0,0 +1,8 @@ |
|||
package com.example.demo.export; |
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class ExportUser { |
|||
private String userName; |
|||
} |
@ -0,0 +1,3 @@ |
|||
|
|||
spring.redis.host=192.168.56.10 |
|||
spring.redis.password=123456 |
Loading…
Reference in new issue