系统集成 onlyoffice

This commit is contained in:
cwchen 2025-11-04 13:24:33 +08:00
parent c474471f65
commit 35245b1a5d
18 changed files with 531 additions and 8 deletions

View File

@ -92,6 +92,12 @@
<artifactId>bonus-template</artifactId> <artifactId>bonus-template</artifactId>
</dependency> </dependency>
<!--招标解析-->
<dependency>
<groupId>com.bonus</groupId>
<artifactId>bonus-analysis</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -0,0 +1,47 @@
package com.bonus.web.controller.common;
import com.bonus.common.core.domain.AjaxResult;
import com.bonus.common.domain.file.vo.OnlyOfficeCallback;
import com.bonus.file.service.OnlyOfficeService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/documents")
@CrossOrigin(origins = "*")
public class DocumentController {
@Resource(name = "OnlyOfficeService")
private OnlyOfficeService onlyOfficeService;
@GetMapping("/config")
public AjaxResult getEditorConfig(
@RequestParam String fileId,
@RequestParam String fileName,
@RequestParam(defaultValue = "view") String mode) {
try {
Map<String, Object> config = onlyOfficeService.getConfigWithToken(fileId, fileName, mode);
// String token = onlyOfficeService.getConfigWithToken(fileId, fileName, mode);
// Map<String, String> response = new HashMap<>();
// response.put("token", token);
return AjaxResult.success(config);
} catch (Exception e) {
return AjaxResult.error();
}
}
@PostMapping("/callback")
public AjaxResult handleCallback(@RequestBody OnlyOfficeCallback callback) {
try {
onlyOfficeService.handleCallback(callback);
return AjaxResult.success();
} catch (Exception e) {
return AjaxResult.error();
}
}
}

View File

@ -4,4 +4,17 @@ minio:
endpoint: http://192.168.0.14:9090 endpoint: http://192.168.0.14:9090
access-key: minio access-key: minio
secret-key: bonus@admin123 secret-key: bonus@admin123
bucket-name: smart-bid bucket-name: smart-bid
# onlyoffice配置
onlyoffice:
document-server: http://192.168.0.14:19840/
secret: N9yleoAAnWNo4VY4Dpe0ihH02LpQOigz
jwt-enabled: false
#minio:
# url: http://127.0.0.1:9005
# endpoint: http://127.0.0.1:9005
# access-key: name
# secret-key: password
# bucket-name: smart-bid

27
bonus-analysis/pom.xml Normal file
View File

@ -0,0 +1,27 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.bonus</groupId>
<artifactId>bonus</artifactId>
<version>3.9.0</version>
</parent>
<artifactId>bonus-analysis</artifactId>
<description>
招标解析
</description>
<!-- 通用工具-->
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.bonus</groupId>
<artifactId>bonus-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,11 @@
package com.bonus.analysis.service;
/**
* @className:test
* @author:cwchen
* @date:2025-11-03-14:57
* @version:1.0
* @description:
*/
public class test {
}

View File

@ -187,6 +187,17 @@
<version>${minio.version}</version> <version>${minio.version}</version>
</dependency> </dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons-fileupload.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${io.jsonwebtoken.version}</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -0,0 +1,20 @@
package com.bonus.common.domain.file.dto;
import lombok.Data;
/**
* @className:OnlyOfficeDto
* @author:cwchen
* @date:2025-11-03-16:28
* @version:1.0
* @description:onlyoffice-文件预览编辑dto
*/
@Data
public class OnlyOfficeDto {
private String fileId;
/**模式*/
private String fileName;
/**模式 view-预览 edit编辑*/
private String mode = "view";
}

View File

@ -0,0 +1,23 @@
package com.bonus.common.domain.file.vo;
import lombok.Data;
import java.util.Date;
/**
* @className:DocumentInfo
* @author:cwchen
* @date:2025-11-04-9:28
* @version:1.0
* @description: onlyoffice
*/
@Data
public class DocumentInfo {
private String id;
private String name;
private String originalName;
private Long size;
private String contentType;
private Date uploadTime;
private Date lastModified;
}

View File

@ -0,0 +1,32 @@
package com.bonus.common.domain.file.vo;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
* @className: OnlyOfficeCallback
* @author: cwchen
* @date: 2025-11-03-16:20
* @version: 1.0
* @description: onlyoffice文件预览回调实体类
*/
@Data
public class OnlyOfficeCallback {
private Integer status;
private String key;
private String url;
private List<Map<String, Object>> actions;
private String lastsave;
private Boolean users;
private Boolean notmodified;
// 状态常量
public static final int STATUS_EDITING = 1; // 文档正在编辑
public static final int STATUS_READY_FOR_SAVE = 2;// 文档已准备好保存
public static final int STATUS_SAVE_ERROR = 3; // 文档保存错误
public static final int STATUS_CLOSED_NO_CHANGES = 4; // 文档已关闭无更改
public static final int STATUS_DOCUMENT_EDITED = 6; // 强制保存
public static final int STATUS_FORCE_SAVE = 7; // 强制保存错误
}

View File

@ -1,7 +1,12 @@
package com.bonus.common.utils; package com.bonus.common.utils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.nio.file.Paths; import java.nio.file.Paths;
@ -166,4 +171,28 @@ public class FileUtil {
return new ByteArrayMultipartFile(fileContent, originalFileName, contentType); return new ByteArrayMultipartFile(fileContent, originalFileName, contentType);
} }
/**
* 创建 MultipartFile 对象
*/
public static MultipartFile createMultipartFile(String fileName, String originalFileName,
String contentType, InputStream inputStream) throws Exception {
// 使用 CommonsMultipartFile
FileItem fileItem = createFileItem(fileName, contentType, inputStream);
return new CommonsMultipartFile(fileItem);
}
private static FileItem createFileItem(String fieldName, String contentType, InputStream inputStream) throws Exception {
DiskFileItemFactory factory = new DiskFileItemFactory();
FileItem fileItem = factory.createItem(fieldName, contentType, false, null);
try (OutputStream os = fileItem.getOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
}
return fileItem;
}
} }

View File

@ -0,0 +1,30 @@
package com.bonus.file.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @className: OnlyOfficeConfig
* @author: cwchen
* @date: 2025-11-03-16:02
* @version: 1.0
* @description: OnlyOffice 配置
*/
@Component(value = "OnlyOfficeConfig")
@Data
public class OnlyOfficeConfig {
@Value("${onlyoffice.document-server}")
private String documentServer;
@Value("${onlyoffice.secret}")
private String jwtSecret;
@Value("${onlyoffice.jwt-enabled}")
private boolean jwtEnabled;
@Value("${server.port}")
private String serverPort;
}

View File

@ -6,10 +6,15 @@ import com.bonus.file.config.MinioConfig;
import com.bonus.file.util.MinioUtil; import com.bonus.file.util.MinioUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -113,4 +118,5 @@ public class FileUploadService {
return fileVoList; return fileVoList;
} }
} }

View File

@ -0,0 +1,41 @@
package com.bonus.file.service;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @className:OnlyOfficeJwtService
* @author:cwchen
* @date:2025-11-04-9:59
* @version:1.0
* @description: onlyoffice jwt 生成
*/
@Component(value = "OnlyOfficeJwtService")
public class OnlyOfficeJwtService {
@Value("${onlyoffice.secret}")
private String jwtSecret;
// 生成 JWT Token
public String generateToken(Map<String, Object> payload) {
// 实现 JWT 生成逻辑
return Jwts.builder()
.setClaims(payload)
.signWith(SignatureAlgorithm.HS256, jwtSecret)
.compact();
}
// 验证 JWT Token
public boolean verifyToken(String token) {
try {
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
}

View File

@ -0,0 +1,217 @@
package com.bonus.file.service;
import com.bonus.common.core.domain.model.LoginUser;
import com.bonus.common.domain.file.vo.OnlyOfficeCallback;
import com.bonus.common.utils.FileUtil;
import com.bonus.common.utils.SecurityUtils;
import com.bonus.file.config.OnlyOfficeConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* @className:OnlyOfficeService
* @author:cwchen
* @date:2025-11-03-16:14
* @version:1.0
* @description:OnlyOffice 服务类
*/
@Service(value = "OnlyOfficeService")
@Slf4j
@CrossOrigin(origins = "*")
public class OnlyOfficeService {
@Resource(name = "FileUploadService")
private FileUploadService fileUploadService;
@Resource(name = "OnlyOfficeJwtService")
private OnlyOfficeJwtService onlyOfficeJwtService;
@Resource(name = "OnlyOfficeConfig")
private OnlyOfficeConfig onlyOfficeConfig;
@Resource
private RedisTemplate<String, Object> redisTemplate;
private static final String DOCUMENT_CACHE_KEY = "document:";
public Map<String, Object> getConfigWithToken(String fileKey, String fileName, String mode) throws Exception {
Map<String, Object> map = buildEditorConfig(fileKey, fileName, mode);
String token = onlyOfficeJwtService.generateToken(map);
map.put("token", token);
return map;
}
public Map<String, Object> buildEditorConfig(String fileKey, String fileName, String mode) throws Exception {
String fileUrl = fileUploadService.getFile(fileName).getUrl();
Map<String, Object> config = new HashMap<>();
// 文档配置
Map<String, Object> document = new HashMap<>();
document.put("title", fileName);
document.put("url", fileUrl);
document.put("fileType", getFileExtension(fileName));
document.put("key", fileKey);
document.put("permissions", buildPermissions(mode));
// 编辑器配置
Map<String, Object> editorConfig = new HashMap<>();
editorConfig.put("mode", mode);
editorConfig.put("lang", "zh-CN");
editorConfig.put("callbackUrl", buildCallbackUrl());
// 用户信息
Map<String, Object> user = new HashMap<>();
user.put("id", getCurrentUserId());
user.put("name", getCurrentUserName());
editorConfig.put("user", user);
// 自定义配置
Map<String, Object> customization = new HashMap<>();
customization.put("forcesave", true);
customization.put("compactToolbar", false);
editorConfig.put("customization", customization);
config.put("document", document);
config.put("documentType", getDocumentType(fileName));
config.put("editorConfig", editorConfig);
config.put("type", "embedded");
config.put("width", "100%");
config.put("height", "600px");
// 缓存文档信息
cacheDocumentInfo(fileKey, fileName);
return config;
}
public void handleCallback(OnlyOfficeCallback callback) {
log.info("收到 OnlyOffice 回调, 状态: {}, Key: {}", callback.getStatus(), callback.getKey());
switch (callback.getStatus()) {
case OnlyOfficeCallback.STATUS_READY_FOR_SAVE:
case OnlyOfficeCallback.STATUS_FORCE_SAVE:
saveDocumentFromCallback(callback);
break;
case OnlyOfficeCallback.STATUS_DOCUMENT_EDITED:
log.info("文档已被编辑: {}", callback.getKey());
break;
case OnlyOfficeCallback.STATUS_CLOSED_NO_CHANGES:
log.info("文档关闭,无更改: {}", callback.getKey());
break;
default:
log.info("文档状态: {}", callback.getStatus());
}
}
private void saveDocumentFromCallback(OnlyOfficeCallback callback) {
try {
String fileName = getCachedFileName(callback.getKey());
if (fileName == null) {
log.error("未找到缓存的文档信息: {}", callback.getKey());
return;
}
// OnlyOffice 下载最新版本
String downloadUrl = callback.getUrl();
byte[] fileContent = downloadFileFromUrl(downloadUrl);
// 保存到 MinIO
saveToMinio(fileName, fileContent);
log.info("文档保存成功: {}", fileName);
} catch (Exception e) {
log.error("保存文档失败", e);
}
}
private byte[] downloadFileFromUrl(String url) throws Exception {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<byte[]> response = restTemplate.getForEntity(url, byte[].class);
return response.getBody();
}
private void saveToMinio(String fileName, byte[] content) throws Exception {
ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
fileUploadService.uploadFile(FileUtil.createMultipartFile(fileName, fileName,
"application/octet-stream", inputStream), fileName);
}
private void cacheDocumentInfo(String fileKey, String fileName) {
redisTemplate.opsForValue().set(DOCUMENT_CACHE_KEY + fileKey, fileName,
Duration.ofHours(1));
}
private String getCachedFileName(String fileKey) {
return (String) redisTemplate.opsForValue().get(DOCUMENT_CACHE_KEY + fileKey);
}
private String buildCallbackUrl() {
return "http://192.168.0.39:" + onlyOfficeConfig.getServerPort() + "/smartBid/documents/callback";
}
private String getFileExtension(String fileName) {
return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
}
private Map<String, Boolean> buildPermissions(String mode) {
Map<String, Boolean> permissions = new HashMap<>();
boolean canEdit = "edit".equals(mode);
permissions.put("edit", canEdit);
permissions.put("download", true);
permissions.put("review", true);
permissions.put("print", true);
permissions.put("copy", true);
return permissions;
}
private String getDocumentType(String fileName) {
String ext = getFileExtension(fileName);
switch (ext) {
case "docx":
case "doc":
case "odt":
case "rtf":
case "txt":
return "text";
case "xlsx":
case "xls":
case "ods":
case "csv":
return "spreadsheet";
case "pptx":
case "ppt":
case "odp":
return "presentation";
case "pdf":
return "pdf";
default:
return "text";
}
}
private Long getCurrentUserId() {
// 获取用户ID
return Optional.ofNullable(SecurityUtils.getLoginUser())
.map(LoginUser::getUserId)
.orElse(null);
}
private String getCurrentUserName() {
// 获取用户名
return Optional.ofNullable(SecurityUtils.getLoginUser())
.map(LoginUser::getUsername)
.orElse(null);
}
}

View File

@ -112,7 +112,7 @@ public class SecurityConfig
.authorizeHttpRequests((requests) -> { .authorizeHttpRequests((requests) -> {
permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll()); permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
// 对于登录login 注册register 验证码captchaImage 允许匿名访问 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
requests.antMatchers("/login", "/register", "/captchaImage","/sys/config/getConfig","/session/check").permitAll() requests.antMatchers("/login", "/register", "/captchaImage","/sys/config/getConfig","/session/check","/documents/callback").permitAll()
// 静态资源可匿名访问 // 静态资源可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()

View File

@ -183,10 +183,10 @@ public class ParamSecureHandler implements AsyncHandlerInterceptor {
log.info("请求失败,当前请求参数不安全!请求地址:\n" + requestUrl + "\n不安全参数" + pname + ":" + value); log.info("请求失败,当前请求参数不安全!请求地址:\n" + requestUrl + "\n不安全参数" + pname + ":" + value);
return false; return false;
} }
if (SafeUtil.checkSpecial(value) || SafeUtil.checkScript(value)) { /*if (SafeUtil.checkSpecial(value) || SafeUtil.checkScript(value)) {
log.info("请求失败,当前请求参数包含特殊字符!请求地址:\n" + requestUrl + "\n特殊字符参数" + pname + ":" + value); log.info("请求失败,当前请求参数包含特殊字符!请求地址:\n" + requestUrl + "\n特殊字符参数" + pname + ":" + value);
return false; return false;
} }*/
} }
} }
return true; return true;

View File

@ -72,7 +72,7 @@ public class XssRequestWrapper extends HttpServletRequestWrapper {
XSS_PATTERNS.add(Pattern.compile("<.*>", Pattern.CASE_INSENSITIVE)); // 尖括号 XSS_PATTERNS.add(Pattern.compile("<.*>", Pattern.CASE_INSENSITIVE)); // 尖括号
XSS_PATTERNS.add(Pattern.compile("\\[.*\\]", Pattern.CASE_INSENSITIVE)); // 方括号 XSS_PATTERNS.add(Pattern.compile("\\[.*\\]", Pattern.CASE_INSENSITIVE)); // 方括号
// XSS_PATTERNS.add(Pattern.compile("\\(.*\\)", Pattern.CASE_INSENSITIVE)); // 圆括号 // XSS_PATTERNS.add(Pattern.compile("\\(.*\\)", Pattern.CASE_INSENSITIVE)); // 圆括号
XSS_PATTERNS.add(Pattern.compile("'.*'", Pattern.CASE_INSENSITIVE)); // 单引号 // XSS_PATTERNS.add(Pattern.compile("'.*'", Pattern.CASE_INSENSITIVE)); // 单引号
XSS_PATTERNS.add(Pattern.compile("\".*\"", Pattern.CASE_INSENSITIVE)); // 双引号 XSS_PATTERNS.add(Pattern.compile("\".*\"", Pattern.CASE_INSENSITIVE)); // 双引号
// 更完善的% 校验 URL编码排除 // 更完善的% 校验 URL编码排除
XSS_PATTERNS.add(Pattern.compile("%(?!(?:[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))", Pattern.CASE_INSENSITIVE)); XSS_PATTERNS.add(Pattern.compile("%(?!(?:[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))", Pattern.CASE_INSENSITIVE));
@ -80,7 +80,7 @@ public class XssRequestWrapper extends HttpServletRequestWrapper {
// URL编码模式 // URL编码模式
XSS_PATTERNS.add(Pattern.compile("%3c", Pattern.CASE_INSENSITIVE)); // < 的URL编码 XSS_PATTERNS.add(Pattern.compile("%3c", Pattern.CASE_INSENSITIVE)); // < 的URL编码
XSS_PATTERNS.add(Pattern.compile("%3e", Pattern.CASE_INSENSITIVE)); // > 的URL编码 XSS_PATTERNS.add(Pattern.compile("%3e", Pattern.CASE_INSENSITIVE)); // > 的URL编码
XSS_PATTERNS.add(Pattern.compile("%2f", Pattern.CASE_INSENSITIVE)); // / 的URL编码 // XSS_PATTERNS.add(Pattern.compile("%2f", Pattern.CASE_INSENSITIVE)); // / 的URL编码
XSS_PATTERNS.add(Pattern.compile("%27", Pattern.CASE_INSENSITIVE)); // ' 的URL编码 XSS_PATTERNS.add(Pattern.compile("%27", Pattern.CASE_INSENSITIVE)); // ' 的URL编码
XSS_PATTERNS.add(Pattern.compile("%22", Pattern.CASE_INSENSITIVE)); // " 的URL编码 XSS_PATTERNS.add(Pattern.compile("%22", Pattern.CASE_INSENSITIVE)); // " 的URL编码
XSS_PATTERNS.add(Pattern.compile("%2b", Pattern.CASE_INSENSITIVE)); // + 的URL编码 XSS_PATTERNS.add(Pattern.compile("%2b", Pattern.CASE_INSENSITIVE)); // + 的URL编码
@ -95,7 +95,7 @@ public class XssRequestWrapper extends HttpServletRequestWrapper {
// 十六进制编码 // 十六进制编码
XSS_PATTERNS.add(Pattern.compile("\\\\x3c", Pattern.CASE_INSENSITIVE)); // < 的十六进制 XSS_PATTERNS.add(Pattern.compile("\\\\x3c", Pattern.CASE_INSENSITIVE)); // < 的十六进制
XSS_PATTERNS.add(Pattern.compile("\\\\x3e", Pattern.CASE_INSENSITIVE)); // > 的十六进制 XSS_PATTERNS.add(Pattern.compile("\\\\x3e", Pattern.CASE_INSENSITIVE)); // > 的十六进制
XSS_PATTERNS.add(Pattern.compile("\\\\x2f", Pattern.CASE_INSENSITIVE)); // / 的十六进制 // XSS_PATTERNS.add(Pattern.compile("\\\\x2f", Pattern.CASE_INSENSITIVE)); // / 的十六进制
XSS_PATTERNS.add(Pattern.compile("\\\\x27", Pattern.CASE_INSENSITIVE)); // ' 的十六进制 XSS_PATTERNS.add(Pattern.compile("\\\\x27", Pattern.CASE_INSENSITIVE)); // ' 的十六进制
XSS_PATTERNS.add(Pattern.compile("\\\\x22", Pattern.CASE_INSENSITIVE)); // " 的十六进制 XSS_PATTERNS.add(Pattern.compile("\\\\x22", Pattern.CASE_INSENSITIVE)); // " 的十六进制
@ -109,7 +109,7 @@ public class XssRequestWrapper extends HttpServletRequestWrapper {
// 1. SQL注释模式 // 1. SQL注释模式
XSS_PATTERNS.add(Pattern.compile("--", Pattern.CASE_INSENSITIVE)); // 单行注释 XSS_PATTERNS.add(Pattern.compile("--", Pattern.CASE_INSENSITIVE)); // 单行注释
XSS_PATTERNS.add(Pattern.compile("/\\*.*?\\*/", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)); // 多行注释 // XSS_PATTERNS.add(Pattern.compile("/\\*.*?\\*/", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)); // 多行注释
// XSS_PATTERNS.add(Pattern.compile("#", Pattern.CASE_INSENSITIVE)); // MySQL注释 // XSS_PATTERNS.add(Pattern.compile("#", Pattern.CASE_INSENSITIVE)); // MySQL注释
// 2. 字符串分隔符 // 2. 字符串分隔符

10
pom.xml
View File

@ -39,6 +39,8 @@
<!-- 强制使用新的 MySQL 连接器坐标 --> <!-- 强制使用新的 MySQL 连接器坐标 -->
<mysql.connector-j.version>8.0.33</mysql.connector-j.version> <mysql.connector-j.version>8.0.33</mysql.connector-j.version>
<minio.version>8.2.2</minio.version> <minio.version>8.2.2</minio.version>
<commons-fileupload.version>1.4</commons-fileupload.version>
<io.jsonwebtoken.version>0.9.1</io.jsonwebtoken.version>
</properties> </properties>
<!-- 依赖声明 --> <!-- 依赖声明 -->
@ -256,6 +258,13 @@
<artifactId>bonus-template</artifactId> <artifactId>bonus-template</artifactId>
<version>${bonus.version}</version> <version>${bonus.version}</version>
</dependency> </dependency>
<!--招标解析-->
<dependency>
<groupId>com.bonus</groupId>
<artifactId>bonus-analysis</artifactId>
<version>${bonus.version}</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
@ -271,6 +280,7 @@
<module>bonus-ocr</module> <module>bonus-ocr</module>
<module>bonus-mainDatabase</module> <module>bonus-mainDatabase</module>
<module>bonus-template</module> <module>bonus-template</module>
<module>bonus-analysis</module>
</modules> </modules>
<packaging>pom</packaging> <packaging>pom</packaging>