系统集成 onlyoffice
This commit is contained in:
parent
c474471f65
commit
35245b1a5d
|
|
@ -92,6 +92,12 @@
|
|||
<artifactId>bonus-template</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--招标解析-->
|
||||
<dependency>
|
||||
<groupId>com.bonus</groupId>
|
||||
<artifactId>bonus-analysis</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -5,3 +5,16 @@ minio:
|
|||
access-key: minio
|
||||
secret-key: bonus@admin123
|
||||
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
|
||||
|
|
@ -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>
|
||||
|
|
@ -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 {
|
||||
}
|
||||
|
|
@ -187,6 +187,17 @@
|
|||
<version>${minio.version}</version>
|
||||
</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>
|
||||
|
||||
</project>
|
||||
|
|
@ -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";
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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; // 强制保存错误
|
||||
}
|
||||
|
|
@ -1,7 +1,12 @@
|
|||
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.commons.CommonsMultipartFile;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.file.Paths;
|
||||
|
|
@ -166,4 +171,28 @@ public class FileUtil {
|
|||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -6,10 +6,15 @@ import com.bonus.file.config.MinioConfig;
|
|||
import com.bonus.file.util.MinioUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.commons.CommonsMultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
|
|
@ -113,4 +118,5 @@ public class FileUploadService {
|
|||
return fileVoList;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -112,7 +112,7 @@ public class SecurityConfig
|
|||
.authorizeHttpRequests((requests) -> {
|
||||
permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
|
||||
// 对于登录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("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
|
||||
|
|
|
|||
|
|
@ -183,10 +183,10 @@ public class ParamSecureHandler implements AsyncHandlerInterceptor {
|
|||
log.info("请求失败,当前请求参数不安全!请求地址:\n" + requestUrl + "\n不安全参数:" + pname + ":" + value);
|
||||
return false;
|
||||
}
|
||||
if (SafeUtil.checkSpecial(value) || SafeUtil.checkScript(value)) {
|
||||
/*if (SafeUtil.checkSpecial(value) || SafeUtil.checkScript(value)) {
|
||||
log.info("请求失败,当前请求参数包含特殊字符!请求地址:\n" + requestUrl + "\n特殊字符参数:" + pname + ":" + value);
|
||||
return false;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -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)); // 双引号
|
||||
// 更完善的% 校验 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));
|
||||
|
|
@ -80,7 +80,7 @@ public class XssRequestWrapper extends HttpServletRequestWrapper {
|
|||
// 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("%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("%22", 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("\\\\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("\\\\x22", Pattern.CASE_INSENSITIVE)); // " 的十六进制
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ public class XssRequestWrapper extends HttpServletRequestWrapper {
|
|||
|
||||
// 1. SQL注释模式
|
||||
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注释
|
||||
|
||||
// 2. 字符串分隔符
|
||||
|
|
|
|||
10
pom.xml
10
pom.xml
|
|
@ -39,6 +39,8 @@
|
|||
<!-- 强制使用新的 MySQL 连接器坐标 -->
|
||||
<mysql.connector-j.version>8.0.33</mysql.connector-j.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>
|
||||
|
||||
<!-- 依赖声明 -->
|
||||
|
|
@ -256,6 +258,13 @@
|
|||
<artifactId>bonus-template</artifactId>
|
||||
<version>${bonus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--招标解析-->
|
||||
<dependency>
|
||||
<groupId>com.bonus</groupId>
|
||||
<artifactId>bonus-analysis</artifactId>
|
||||
<version>${bonus.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
|
@ -271,6 +280,7 @@
|
|||
<module>bonus-ocr</module>
|
||||
<module>bonus-mainDatabase</module>
|
||||
<module>bonus-template</module>
|
||||
<module>bonus-analysis</module>
|
||||
</modules>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue