22 changed files with 913 additions and 339 deletions
@ -1,141 +0,0 @@
@@ -1,141 +0,0 @@
|
||||
|
||||
package apelet.tenantadmin.tenant.controller; |
||||
|
||||
import apelet.common.core.annotation.MyRequestBody; |
||||
import apelet.common.core.exception.MyRuntimeException; |
||||
import apelet.common.core.object.ObjectValue; |
||||
import apelet.common.generator.utils.OrmGenDataSourceUtil; |
||||
import cn.hutool.core.io.IoUtil; |
||||
import org.apache.poi.xwpf.usermodel.*; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.core.io.ClassPathResource; |
||||
import org.springframework.web.bind.annotation.*; |
||||
|
||||
import javax.servlet.http.HttpServletResponse; |
||||
import java.io.*; |
||||
import java.net.URLEncoder; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
@RestController |
||||
@RequestMapping("/api/template") |
||||
public class DocxTemplateController { |
||||
|
||||
|
||||
@Autowired |
||||
private OrmGenDataSourceUtil ormGenDataSourceUtil; |
||||
|
||||
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{(.+?)\\}"); |
||||
|
||||
/** |
||||
* 替换字符串中 ${key},JDK8兼容 |
||||
*/ |
||||
private String replaceContent(String text, Map<String, Object> dataMap) { |
||||
if (text == null) return ""; |
||||
Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); |
||||
StringBuffer sb = new StringBuffer(); |
||||
while (matcher.find()) { |
||||
String key = matcher.group(1).trim(); |
||||
Object val = dataMap.get(key); |
||||
String realVal = val == null ? "" : val.toString(); |
||||
matcher.appendReplacement(sb, Matcher.quoteReplacement(realVal)); |
||||
} |
||||
matcher.appendTail(sb); |
||||
return sb.toString(); |
||||
} |
||||
|
||||
@GetMapping("/downloadDocx") |
||||
public void downloadDocx(@RequestParam("id") String quotationId, HttpServletResponse response) { |
||||
XWPFDocument document = null; |
||||
InputStream templateIs = null; |
||||
OutputStream out = null; |
||||
try { |
||||
// 1. 查数据
|
||||
ObjectValue objectValue = ormGenDataSourceUtil.queryOne("quotation", quotationId); |
||||
Map<String, Object> hashMap = new HashMap<>(); |
||||
hashMap.put("name", objectValue.getString("name")); |
||||
hashMap.put("number", objectValue.getString("number")); |
||||
hashMap.put("create_time", objectValue.getString("create_time")); |
||||
hashMap.put("qty", objectValue.getObjectValue("qty")); |
||||
ObjectValue managerperson = objectValue.getObjectValue("managerperson"); |
||||
if(managerperson != null){ |
||||
managerperson = ormGenDataSourceUtil.queryOne(managerperson.getTableName(), managerperson.getString("id")); |
||||
hashMap.put("managerperson",1); |
||||
} |
||||
// 2. 读模板
|
||||
File file = new File("D:\\work\\xykj-project\\xhgl\\zz-resource\\quotation_template.docx"); |
||||
templateIs = new FileInputStream(file); |
||||
document = new XWPFDocument(templateIs); |
||||
// 3. 替换占位符
|
||||
replaceParagraph(document, hashMap); |
||||
replaceTable(document, hashMap); |
||||
// 4. 设置响应头 —— 关键!
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"); |
||||
response.setCharacterEncoding("UTF-8"); |
||||
String fileName = URLEncoder.encode("报价单.docx", StandardCharsets.UTF_8.name()) |
||||
.replaceAll("\\+", "%20"); |
||||
// 兼容各浏览器的文件名写法
|
||||
response.setHeader("Content-Disposition", |
||||
"attachment; filename=\"" + fileName + "\"; filename*=UTF-8''" + fileName); |
||||
response.setHeader("Pragma", "no-cache"); |
||||
response.setHeader("Cache-Control", "no-cache"); |
||||
response.setDateHeader("Expires", 0); |
||||
// 5. 写出
|
||||
out = response.getOutputStream(); |
||||
document.write(out); |
||||
out.flush(); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
throw new MyRuntimeException("导出失败: " + e.getMessage()); |
||||
} finally { |
||||
IoUtil.close(document); |
||||
IoUtil.close(templateIs); |
||||
IoUtil.close(out); |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
private void replaceParagraph(XWPFDocument document, Map<String, Object> dataMap) { |
||||
for (XWPFParagraph paragraph : document.getParagraphs()) { |
||||
String text = paragraph.getText(); |
||||
Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); |
||||
if (!matcher.find()) { |
||||
continue; |
||||
} |
||||
//清空原有run
|
||||
for (XWPFRun run : paragraph.getRuns()) { |
||||
run.setText("", 0); |
||||
} |
||||
String newText = replaceContent(text, dataMap); |
||||
paragraph.createRun().setText(newText); |
||||
} |
||||
} |
||||
|
||||
private void replaceTable(XWPFDocument document, Map<String, Object> dataMap) { |
||||
for (XWPFTable table : document.getTables()) { |
||||
for (XWPFTableRow row : table.getRows()) { |
||||
for (XWPFTableCell cell : row.getTableCells()) { |
||||
for (XWPFParagraph paragraph : cell.getParagraphs()) { |
||||
String text = paragraph.getText(); |
||||
Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); |
||||
if (!matcher.find()) { |
||||
continue; |
||||
} |
||||
for (XWPFRun run : paragraph.getRuns()) { |
||||
run.setText("", 0); |
||||
} |
||||
String newText = replaceContent(text, dataMap); |
||||
paragraph.createRun().setText(newText); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
@ -0,0 +1,353 @@
@@ -0,0 +1,353 @@
|
||||
package apelet.tenantadmin.upms.controller; |
||||
|
||||
import apelet.common.core.exception.MyRuntimeException; |
||||
import apelet.common.core.object.ObjectCollection; |
||||
import apelet.common.core.object.ObjectValue; |
||||
import apelet.common.core.object.ResponseResult; |
||||
import apelet.common.generator.utils.OrmGenDataSourceUtil; |
||||
import apelet.common.online.service.OnlineDictService; |
||||
import apelet.common.orm.impl.Filter; |
||||
import apelet.common.orm.impl.Selector; |
||||
import cn.hutool.core.date.DateUtil; |
||||
import cn.hutool.core.io.IoUtil; |
||||
import cn.hutool.poi.excel.ExcelReader; |
||||
import cn.hutool.poi.excel.ExcelUtil; |
||||
import com.alibaba.fastjson.JSON; |
||||
import com.alibaba.fastjson.JSONArray; |
||||
import com.alibaba.fastjson.JSONObject; |
||||
|
||||
import org.apache.commons.lang3.StringUtils; |
||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; |
||||
import org.apache.poi.xwpf.usermodel.*; |
||||
import org.docx4j.Docx4J; |
||||
import org.docx4j.fonts.IdentityPlusMapper; |
||||
import org.docx4j.fonts.PhysicalFonts; |
||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.web.bind.annotation.*; |
||||
import org.springframework.web.multipart.MultipartFile; |
||||
|
||||
import javax.servlet.http.HttpServletResponse; |
||||
import java.io.*; |
||||
import java.net.HttpURLConnection; |
||||
import java.net.URL; |
||||
import java.net.URLEncoder; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.nio.file.Files; |
||||
import java.util.*; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
import java.util.stream.Collectors; |
||||
|
||||
@RestController |
||||
@RequestMapping("/api/template") |
||||
public class DocxTemplateController { |
||||
|
||||
@Autowired |
||||
private OrmGenDataSourceUtil ormGenDataSourceUtil; |
||||
@Autowired |
||||
private OnlineDictService onlineDictService; |
||||
|
||||
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("#\\{(.+?)\\}"); |
||||
|
||||
private String replaceContent(String text, Map<String, Object> dataMap) { |
||||
if (text == null) return ""; |
||||
Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); |
||||
StringBuffer sb = new StringBuffer(); |
||||
while (matcher.find()) { |
||||
String key = matcher.group(1).trim(); |
||||
if ("personimage".equals(key)) { |
||||
matcher.appendReplacement(sb, Matcher.quoteReplacement(matcher.group(0))); |
||||
continue; |
||||
} |
||||
Object val = dataMap.get(key); |
||||
String realVal = val == null ? "" : val.toString(); |
||||
matcher.appendReplacement(sb, Matcher.quoteReplacement(realVal)); |
||||
} |
||||
matcher.appendTail(sb); |
||||
return sb.toString(); |
||||
} |
||||
|
||||
|
||||
@GetMapping("/downloadDocx") |
||||
public void downloadDocx(@RequestParam("id") String quotationId, @RequestParam("userId") String userId, HttpServletResponse response) { |
||||
XWPFDocument document = null; |
||||
InputStream templateIs = null; |
||||
OutputStream out = null; |
||||
ByteArrayOutputStream pdfOut = null; |
||||
try { |
||||
// 1. 查数据
|
||||
ObjectValue objectValue = ormGenDataSourceUtil.queryOne("quotation", quotationId); |
||||
ObjectValue user = ormGenDataSourceUtil.queryOne("xy_sys_user", userId); |
||||
Map<String, String> dictMap = onlineDictService.getDictMap(2052225870772310016L); |
||||
Map<String, Object> hashMap = new HashMap<>(); |
||||
hashMap.put("name", objectValue.getString("name")); |
||||
hashMap.put("type", dictMap.get(String.valueOf(objectValue.get("type", "")))); |
||||
hashMap.put("number", objectValue.getString("number")); |
||||
hashMap.put("create_time", objectValue.getString("create_time").substring(0, 10)); |
||||
hashMap.put("qty", objectValue.getString("qty")); |
||||
|
||||
String signatureImage = user.getString("signature_image"); |
||||
String imageUrl = getUrl(signatureImage); |
||||
byte[] imageBytes = null; |
||||
if (StringUtils.isNotEmpty(imageUrl)) { |
||||
imageBytes = downloadImage(imageUrl); |
||||
} |
||||
ObjectValue managerperson = objectValue.getObjectValue("managerperson"); |
||||
if (managerperson != null) { |
||||
managerperson = ormGenDataSourceUtil.queryOne(managerperson.getTableName(), managerperson.getString("id")); |
||||
hashMap.put("managerperson", managerperson.getString("show_name")); |
||||
} |
||||
// 2. 读模板
|
||||
String savePath = System.getProperty("user.dir") + "\\zz-resource\\"; |
||||
File file = new File(savePath + "quotation_template.docx"); |
||||
templateIs = Files.newInputStream(file.toPath()); |
||||
document = new XWPFDocument(templateIs); |
||||
// 3. 替换文本占位符
|
||||
replaceParagraph(document, hashMap); |
||||
replaceTable(document, hashMap); |
||||
// 4. 替换图片占位符
|
||||
replaceImageInParagraphs(document, "personimage", imageBytes, 100, 100); |
||||
replaceImageInTables(document, "personimage", imageBytes, 100, 100); |
||||
// 5. 将填充后的 DOCX 转为 PDF(使用 docx4j)
|
||||
ByteArrayOutputStream docxOut = new ByteArrayOutputStream(); |
||||
document.write(docxOut); |
||||
byte[] docxBytes = docxOut.toByteArray(); |
||||
docxOut.close(); |
||||
|
||||
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new ByteArrayInputStream(docxBytes)); |
||||
PhysicalFonts.discoverPhysicalFonts(); |
||||
wordMLPackage.setFontMapper(new IdentityPlusMapper()); |
||||
pdfOut = new ByteArrayOutputStream(); |
||||
Docx4J.toPDF(wordMLPackage, pdfOut); |
||||
byte[] pdfBytes = pdfOut.toByteArray(); |
||||
|
||||
// 6. 设置响应头
|
||||
response.setContentType("application/pdf"); |
||||
response.setCharacterEncoding("UTF-8"); |
||||
String fileName = URLEncoder.encode("报价单.pdf", StandardCharsets.UTF_8.name()) |
||||
.replaceAll("\\+", "%20"); |
||||
response.setHeader("Content-Disposition", |
||||
"attachment; filename=\"" + fileName + "\"; filename*=UTF-8''" + fileName); |
||||
response.setHeader("Pragma", "no-cache"); |
||||
response.setHeader("Cache-Control", "no-cache"); |
||||
response.setDateHeader("Expires", 0); |
||||
// 7. 写出 PDF
|
||||
out = response.getOutputStream(); |
||||
out.write(pdfBytes); |
||||
out.flush(); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
throw new MyRuntimeException("导出失败: " + e.getMessage()); |
||||
} finally { |
||||
IoUtil.close(pdfOut); |
||||
IoUtil.close(document); |
||||
IoUtil.close(templateIs); |
||||
IoUtil.close(out); |
||||
} |
||||
} |
||||
|
||||
|
||||
String getUrl(String signatureImage) { |
||||
if (StringUtils.isEmpty(signatureImage)) { |
||||
return ""; |
||||
} |
||||
JSONArray jsonArray = JSON.parseArray(signatureImage); |
||||
if (jsonArray.isEmpty()) { |
||||
return ""; |
||||
} |
||||
JSONObject jsonObject = jsonArray.getJSONObject(0); |
||||
String baseUrl = jsonObject.getString("baseUrl"); |
||||
String uploadPath = jsonObject.getString("uploadPath"); |
||||
String filename = jsonObject.getString("filename"); |
||||
|
||||
return baseUrl + "/" + uploadPath + "/" + filename; |
||||
} |
||||
|
||||
private void replaceParagraph(XWPFDocument document, Map<String, Object> dataMap) { |
||||
for (XWPFParagraph paragraph : document.getParagraphs()) { |
||||
String text = paragraph.getText(); |
||||
Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); |
||||
if (!matcher.find()) { |
||||
continue; |
||||
} |
||||
for (XWPFRun run : paragraph.getRuns()) { |
||||
run.setText("", 0); |
||||
} |
||||
String newText = replaceContent(text, dataMap); |
||||
paragraph.createRun().setText(newText); |
||||
} |
||||
} |
||||
|
||||
private void replaceTable(XWPFDocument document, Map<String, Object> dataMap) { |
||||
for (XWPFTable table : document.getTables()) { |
||||
for (XWPFTableRow row : table.getRows()) { |
||||
for (XWPFTableCell cell : row.getTableCells()) { |
||||
for (XWPFParagraph paragraph : cell.getParagraphs()) { |
||||
String text = paragraph.getText(); |
||||
Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); |
||||
if (!matcher.find()) { |
||||
continue; |
||||
} |
||||
for (XWPFRun run : paragraph.getRuns()) { |
||||
run.setText("", 0); |
||||
} |
||||
String newText = replaceContent(text, dataMap); |
||||
paragraph.createRun().setText(newText); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
private byte[] downloadImage(String imageUrl) throws IOException { |
||||
URL url = new URL(imageUrl); |
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); |
||||
conn.setRequestMethod("GET"); |
||||
conn.setConnectTimeout(5000); |
||||
conn.setReadTimeout(10000); |
||||
InputStream is = conn.getInputStream(); |
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
||||
byte[] buffer = new byte[4096]; |
||||
int len; |
||||
while ((len = is.read(buffer)) != -1) { |
||||
baos.write(buffer, 0, len); |
||||
} |
||||
IoUtil.close(is); |
||||
return baos.toByteArray(); |
||||
} |
||||
|
||||
|
||||
private void replaceImageInParagraphs(XWPFDocument document, String placeholderKey, byte[] imageBytes, int width, int height) throws IOException, InvalidFormatException { |
||||
String placeholder = "#{" + placeholderKey + "}"; |
||||
for (XWPFParagraph paragraph : document.getParagraphs()) { |
||||
String text = paragraph.getText(); |
||||
if (text != null && text.contains(placeholder)) { |
||||
List<XWPFRun> runs = paragraph.getRuns(); |
||||
for (int i = runs.size() - 1; i >= 0; i--) { |
||||
XWPFRun run = runs.get(i); |
||||
String runText = run.getText(0); |
||||
if (runText != null && runText.contains(placeholder)) { |
||||
run.setText("", 0); |
||||
if (imageBytes != null) { |
||||
run.addPicture(new ByteArrayInputStream(imageBytes), XWPFDocument.PICTURE_TYPE_PNG, placeholderKey + ".png", |
||||
width * 9525, height * 9525); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void replaceImageInTables(XWPFDocument document, String placeholderKey, byte[] imageBytes, int width, int height) throws IOException, InvalidFormatException { |
||||
String placeholder = "#{" + placeholderKey + "}"; |
||||
for (XWPFTable table : document.getTables()) { |
||||
for (XWPFTableRow row : table.getRows()) { |
||||
for (XWPFTableCell cell : row.getTableCells()) { |
||||
for (XWPFParagraph paragraph : cell.getParagraphs()) { |
||||
String text = paragraph.getText(); |
||||
if (text != null && text.contains(placeholder)) { |
||||
List<XWPFRun> runs = paragraph.getRuns(); |
||||
for (int i = runs.size() - 1; i >= 0; i--) { |
||||
XWPFRun run = runs.get(i); |
||||
String runText = run.getText(0); |
||||
if (runText != null && runText.contains(placeholder)) { |
||||
run.setText("", 0); |
||||
if (imageBytes != null) { |
||||
run.addPicture(new ByteArrayInputStream(imageBytes), XWPFDocument.PICTURE_TYPE_PNG, placeholderKey + ".png", |
||||
width * 9525, height * 9525); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
private static final Map<String, String> HEADER_MAP = new LinkedHashMap<>(); |
||||
|
||||
static { |
||||
HEADER_MAP.put("名称", "name"); |
||||
HEADER_MAP.put("性别", "gender"); |
||||
HEADER_MAP.put("手机号码", "phone"); |
||||
HEADER_MAP.put("出生年月", "birth_date"); |
||||
HEADER_MAP.put("学历", "education"); |
||||
HEADER_MAP.put("民族", "nation"); |
||||
HEADER_MAP.put("政治面貌", "political_status"); |
||||
HEADER_MAP.put("身份证号码", "id_card"); |
||||
HEADER_MAP.put("毕业院校", "graduate_school"); |
||||
HEADER_MAP.put("所属专业", "major"); |
||||
HEADER_MAP.put("常住地", "permanent_address"); |
||||
} |
||||
|
||||
@PostMapping("/expertImport") |
||||
public ResponseResult<?> expertImport(@RequestParam("file") MultipartFile file) { |
||||
List<Map<String, Object>> dataList = new ArrayList<>(); |
||||
try (InputStream is = file.getInputStream()) { |
||||
ExcelReader reader = ExcelUtil.getReader(is); |
||||
// 第一行作为表头,key 为表头名称,自动兼容 xls/xlsx
|
||||
List<Map<String, Object>> rawList = reader.readAll(); |
||||
//学历
|
||||
Map<String, String> educationDictMap = onlineDictService.getDictMap(2054094099727781888L); |
||||
educationDictMap = educationDictMap.entrySet().stream() |
||||
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey)); |
||||
//政治面貌
|
||||
Map<String, String> politicalDictMap = onlineDictService.getDictMap(2054098587905691648L); |
||||
politicalDictMap = politicalDictMap.entrySet().stream() |
||||
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey)); |
||||
for (Map<String, Object> row : rawList) { |
||||
Map<String, Object> dataMap = new LinkedHashMap<>(); |
||||
|
||||
for (Map.Entry<String, Object> entry : row.entrySet()) { |
||||
String header = entry.getKey() == null ? "" : entry.getKey().trim(); |
||||
// 中文表头转英文,映射中没有的表头保留原值
|
||||
String key = HEADER_MAP.getOrDefault(header, header); |
||||
Object value = entry.getValue(); |
||||
dataMap.put(key, value); |
||||
if (key.equals("gender")) { |
||||
dataMap.put("gender", value.equals("男") ? "1" : "0"); |
||||
} |
||||
if (key.equals("education")) { |
||||
dataMap.put("education", educationDictMap.get(value.toString())); |
||||
} |
||||
if (key.equals("political_status")) { |
||||
dataMap.put("political_status", politicalDictMap.get(value.toString())); |
||||
} |
||||
if ("birth_date".equals(key)) { |
||||
if (value instanceof Date) { |
||||
value = DateUtil.formatDateTime((Date) value); |
||||
} else if (value instanceof String && StringUtils.isNotBlank((String) value)) { |
||||
value = DateUtil.formatDateTime(DateUtil.parse((String) value)); |
||||
} |
||||
dataMap.put(key, value); |
||||
} |
||||
} |
||||
dataMap.put("billstatus", "A"); |
||||
dataMap.put("apply_time", DateUtil.formatDateTime(new Date())); |
||||
dataList.add(dataMap); |
||||
} |
||||
ObjectCollection expertManage = ormGenDataSourceUtil.query("expert_manage", new Filter(), new Selector()); |
||||
dataList.forEach(dataMap -> { |
||||
long count = expertManage.stream().filter(f -> f.get("id_card").equals(dataMap.get("id_card"))).count(); |
||||
if (count > 0) { |
||||
return; |
||||
} |
||||
ObjectValue value = new ObjectValue("expert_manage"); |
||||
value.setValues(dataMap); |
||||
try { |
||||
ormGenDataSourceUtil.addNew("expert_manage", value); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
}); |
||||
|
||||
} catch (IOException e) { |
||||
throw new MyRuntimeException("文件解析失败: " + e.getMessage()); |
||||
} |
||||
return ResponseResult.success("导入成功"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,121 @@
@@ -0,0 +1,121 @@
|
||||
package apelet.tenantadmin.upms.service; |
||||
|
||||
import cn.hutool.http.HttpRequest; |
||||
import cn.hutool.http.HttpResponse; |
||||
import com.alibaba.fastjson.JSON; |
||||
import com.alibaba.fastjson.JSONObject; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.redisson.api.RBucket; |
||||
import org.redisson.api.RedissonClient; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.beans.factory.annotation.Value; |
||||
import org.springframework.stereotype.Service; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
@Slf4j |
||||
@Service |
||||
public class SupersetSsoService { |
||||
|
||||
@Value("${superset.baseUrl}") |
||||
private String supersetBaseUrl; |
||||
|
||||
@Value("${superset.username}") |
||||
private String supersetUsername; |
||||
|
||||
@Value("${superset.password}") |
||||
private String supersetPassword; |
||||
|
||||
@Autowired |
||||
private RedissonClient redissonClient; |
||||
|
||||
private static final String SUPERSET_TOKEN_CACHE_KEY = "superset:access_token"; |
||||
private static final int TOKEN_CACHE_SECONDS = 3500; |
||||
|
||||
public String getAccessToken() { |
||||
RBucket<String> cached = redissonClient.getBucket(SUPERSET_TOKEN_CACHE_KEY); |
||||
if (cached.isExists()) { |
||||
return cached.get(); |
||||
} |
||||
String url = supersetBaseUrl + "/api/v1/security/login"; |
||||
JSONObject payload = new JSONObject(); |
||||
payload.put("username", supersetUsername); |
||||
payload.put("password", supersetPassword); |
||||
payload.put("provider", "db"); |
||||
payload.put("refresh", true); |
||||
|
||||
HttpResponse response = HttpRequest.post(url) |
||||
.header("Content-Type", "application/json") |
||||
.body(payload.toJSONString()) |
||||
.timeout(10000) |
||||
.execute(); |
||||
|
||||
if (!response.isOk()) { |
||||
log.error("Superset login failed, status={}, body={}", response.getStatus(), response.body()); |
||||
throw new RuntimeException("Superset认证失败: " + response.body()); |
||||
} |
||||
|
||||
JSONObject result = JSON.parseObject(response.body()); |
||||
String accessToken = result.getString("access_token"); |
||||
|
||||
cached.set(accessToken, TOKEN_CACHE_SECONDS, TimeUnit.SECONDS); |
||||
log.info("Superset access token refreshed successfully."); |
||||
return accessToken; |
||||
} |
||||
|
||||
public String getGuestToken(String dashboardId, String username, String firstName, String lastName, |
||||
List<Map<String, String>> rlsRules) { |
||||
String accessToken = getAccessToken(); |
||||
|
||||
String url = supersetBaseUrl + "/api/v1/security/guest_token/"; |
||||
|
||||
JSONObject user = new JSONObject(); |
||||
user.put("username", username); |
||||
user.put("first_name", firstName); |
||||
user.put("last_name", lastName); |
||||
|
||||
List<Map<String, Object>> resources = new ArrayList<>(); |
||||
Map<String, Object> resource = new HashMap<>(); |
||||
resource.put("type", "dashboard"); |
||||
resource.put("id", dashboardId); |
||||
resources.add(resource); |
||||
|
||||
JSONObject payload = new JSONObject(); |
||||
payload.put("user", user); |
||||
payload.put("resources", resources); |
||||
if (rlsRules != null && !rlsRules.isEmpty()) { |
||||
payload.put("rls", rlsRules); |
||||
} else { |
||||
payload.put("rls", new ArrayList<>()); |
||||
} |
||||
|
||||
HttpResponse response = HttpRequest.post(url) |
||||
.header("Content-Type", "application/json") |
||||
.header("Authorization", "Bearer " + accessToken) |
||||
.body(payload.toJSONString()) |
||||
.timeout(10000) |
||||
.execute(); |
||||
|
||||
if (!response.isOk()) { |
||||
log.error("Superset get guest token failed, status={}, body={}", response.getStatus(), response.body()); |
||||
redissonClient.getBucket(SUPERSET_TOKEN_CACHE_KEY).delete(); |
||||
throw new RuntimeException("获取Superset Guest Token失败: " + response.body()); |
||||
} |
||||
|
||||
JSONObject result = JSON.parseObject(response.body()); |
||||
return result.getString("token"); |
||||
} |
||||
|
||||
public String buildDashboardUrl(String dashboardId) { |
||||
String accessToken = getAccessToken(); |
||||
return supersetBaseUrl + "superset/dashboard/" + dashboardId + "/?token=" + accessToken; |
||||
} |
||||
|
||||
public String buildEmbeddedDashboardUrl(String dashboardId, String guestToken) { |
||||
return supersetBaseUrl + "superset/embed/dashboard/" + dashboardId + "/?guest_token=" + guestToken; |
||||
} |
||||
} |
||||
@ -0,0 +1,48 @@
@@ -0,0 +1,48 @@
|
||||
package apelet.association.plugin.active; |
||||
|
||||
import apelet.common.core.object.ObjectCollection; |
||||
import apelet.common.core.object.ObjectValue; |
||||
import apelet.common.core.util.ApplicationContextHolder; |
||||
import apelet.common.generator.utils.OrmGenDataSourceUtil; |
||||
import apelet.common.online.plugin.EndOperationTransactionArgs; |
||||
import apelet.common.online.plugin.OperationServicePlugIn; |
||||
import apelet.common.orm.impl.Filter; |
||||
import apelet.common.orm.impl.FilterItem; |
||||
import apelet.common.orm.impl.Selector; |
||||
|
||||
public class ActivityInvitationSavePlugin extends OperationServicePlugIn { |
||||
|
||||
private OrmGenDataSourceUtil ormGenDataSourceUtil; |
||||
|
||||
public ActivityInvitationSavePlugin() { |
||||
ormGenDataSourceUtil = ApplicationContextHolder.getBean(OrmGenDataSourceUtil.class); |
||||
} |
||||
|
||||
@Override |
||||
public void endOperationTransaction(EndOperationTransactionArgs e) { |
||||
ObjectValue objectValue = e.getModel(); |
||||
ObjectCollection collection = objectValue.getObjectCollection("visitor_invitation"); |
||||
if(collection == null){ |
||||
return; |
||||
} |
||||
Filter filter = new Filter(); |
||||
filter.add(new FilterItem("parent_id", FilterItem.equals, objectValue.get("id"))); |
||||
ObjectCollection visitorInvitationHis = ormGenDataSourceUtil.query("visitor_invitation_his", filter, new Selector()); |
||||
|
||||
for (ObjectValue value : collection) { |
||||
long count = visitorInvitationHis.stream().filter(f -> f.get("name").equals(value.get("name")) && |
||||
f.get("unit_name").equals(value.get("unit_name"))).count(); |
||||
if(count == 0){ |
||||
continue; |
||||
} |
||||
ObjectValue invitationHis = new ObjectValue("visitor_invitation_his"); |
||||
invitationHis.setValues(value.getValues()); |
||||
invitationHis.remove("id"); |
||||
try { |
||||
ormGenDataSourceUtil.addNew(invitationHis.getTableName(), invitationHis); |
||||
} catch (Exception ex) { |
||||
|
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,48 @@
@@ -0,0 +1,48 @@
|
||||
package apelet.association.plugin.member; |
||||
|
||||
import apelet.common.core.exception.MyRuntimeException; |
||||
import apelet.common.core.object.ObjectCollection; |
||||
import apelet.common.core.object.ObjectValue; |
||||
import apelet.common.core.util.ApplicationContextHolder; |
||||
import apelet.common.generator.utils.OrmGenDataSourceUtil; |
||||
import apelet.common.online.abstractplugin.ExecutePluginParent; |
||||
import apelet.common.online.abstractplugin.ListPlugin; |
||||
import apelet.common.online.dto.OnlineEventPluginExecuteDto; |
||||
import apelet.common.online.model.constant.AttributeEnum; |
||||
import apelet.common.orm.impl.Filter; |
||||
import apelet.common.orm.impl.FilterItem; |
||||
import apelet.common.orm.impl.Selector; |
||||
|
||||
import java.sql.Date; |
||||
import java.util.Map; |
||||
import java.util.Optional; |
||||
|
||||
|
||||
public class MembershipBenefitsUpdatePlugin extends ListPlugin { |
||||
|
||||
private OrmGenDataSourceUtil ormGenDataSourceUtil; |
||||
|
||||
public MembershipBenefitsUpdatePlugin() { |
||||
ormGenDataSourceUtil = ApplicationContextHolder.getBean(OrmGenDataSourceUtil.class); |
||||
} |
||||
|
||||
@Override |
||||
public void formCreated(String widgetVariableName, ObjectValue objectValue) { |
||||
ObjectValue value = ormGenDataSourceUtil.queryOne(objectValue.getTableName(), objectValue.getString("id")); |
||||
ObjectCollection collection = value.getObjectCollection("equity_services"); |
||||
ObjectCollection equityServices = objectValue.getObjectCollection("equity_services"); |
||||
for (ObjectValue equityService : equityServices) { |
||||
Optional<ObjectValue> first = collection.stream().filter(f -> f.getString("id").equals(equityService.getString("id"))).findFirst(); |
||||
ObjectValue value1 = first.get(); |
||||
this.setWidgetAttributeByEntry("table1782205467614", "member", |
||||
AttributeEnum.VALUE_CHANGE, value1.getInt("member"), equityService.getString("rowkey")); |
||||
this.setWidgetAttributeByEntry("table1782205467614", "director", |
||||
AttributeEnum.VALUE_CHANGE, value1.getInt("director"), equityService.getString("rowkey")); |
||||
this.setWidgetAttributeByEntry("table1782205467614", "executive_director", |
||||
AttributeEnum.VALUE_CHANGE, value1.getInt("executive_director"), equityService.getString("rowkey")); |
||||
this.setWidgetAttributeByEntry("table1782205467614", "vice_president", |
||||
AttributeEnum.VALUE_CHANGE, value1.getInt("vice_president"), equityService.getString("rowkey")); |
||||
} |
||||
} |
||||
} |
||||
|
||||
Loading…
Reference in new issue