Compare commits

...

22 Commits

Author SHA1 Message Date
DB
d724a9e72a 调整普通微信支付 2024-06-14 16:54:12 +08:00
DB
b97031b4dd 调整品牌校区数据获取,调整依赖,调整校区插件,调整上传 2024-06-13 17:40:43 +08:00
DB
cc11addd6b 技术工具 2024-05-31 11:48:36 +08:00
DB
0528e1feaa 调整系统管理,调整财务管理,添加工单需求 2024-05-28 18:29:14 +08:00
DB
cb9d57b491 1.1.2:重构项目,移除多余依赖,移除多余工具类,调整项目代码,更新版本信息 2024-05-27 15:15:26 +08:00
DB
faac66c57e 开放平台回调 2024-05-09 17:59:53 +08:00
DB
edc54ea5e3 Oam1.1.2;调整开放平台;调整菜单;调整登录;调整角色;调整任务;调整工单;调整路由 2024-05-08 15:58:48 +08:00
DB
34a4950925 工单 2024-04-27 23:33:09 +08:00
DB
de05445ab2 1.1.1 2024-04-26 17:43:46 +08:00
DB
dec1629100 调整部门,员工,字典 2024-04-26 17:00:13 +08:00
DB
5a78ad69c8 调整部门,员工,字典 2024-04-25 18:22:46 +08:00
DB
63a16aa6d1 调整登录,菜单,角色 2024-04-25 13:00:26 +08:00
DB
ce01210aab 调整Oam登录退出获取用户信息 2024-04-24 15:58:04 +08:00
DB
25773526cd Java8->Java17(二) 2024-04-23 18:24:30 +08:00
DB
69dbc94b48 Java8->Java17(一) 2024-04-23 14:39:14 +08:00
DB
e489bde765 调整操作日志 2024-04-22 09:39:28 +08:00
DB
b01aa886c5 调整市场模块 2024-04-19 10:34:00 +08:00
DB
41bdad5ab4 修改品管controller 2024-04-18 17:23:07 +08:00
DB
7b38a28e0c 调整oam配置;调整日志打印 2024-04-18 11:13:12 +08:00
DB
5bbca4104c 调整支付包;调整系统包 2024-04-18 09:41:19 +08:00
DB
45385c0cdd 移除common模块;调整Api,ClockIn,Core,Generator模块 2024-04-17 11:21:41 +08:00
DB
ed9162bf9e 升级Springboot3;升级Java17; 2024-04-16 18:31:46 +08:00
885 changed files with 9834 additions and 42582 deletions

3
.gitignore vendored
View File

@ -3,7 +3,8 @@ target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
**/src/main/resources/static/keyPair/*
**/src/main/resources/static/keypair/*
**/logs/*
### STS ###
.apt_generated

View File

@ -5,7 +5,7 @@
<parent>
<groupId>com.cpop</groupId>
<artifactId>Cpop-Union</artifactId>
<version>1.0.0</version>
<version>1.1.2</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>Cpop-Api</artifactId>

View File

@ -1,7 +1,6 @@
package com.cpop.api.cloudDb.core.dto;
import com.google.gson.annotations.SerializedName;
import io.swagger.models.auth.In;
import lombok.Data;
import java.util.List;

View File

@ -1,9 +1,8 @@
package com.cpop.api.cloudDb.handler;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSONObject;
import com.cpop.api.cloudDb.core.constant.CloudDbUrl;
import com.cpop.api.cloudDb.core.dto.CloudBrandDto;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.exception.UtilException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

View File

@ -1,10 +1,10 @@
package com.cpop.api.cloudDb.handler;
import com.alibaba.fastjson.JSONObject;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.cpop.api.cloudDb.core.constant.CloudDbUrl;
import com.cpop.api.cloudDb.core.dto.CloudClassCardDto;
import com.cpop.api.cloudDb.core.dto.CloudClassCardRecordDto;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.entity.ExtendPage;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.exception.UtilException;
@ -50,17 +50,17 @@ public class CloudClassCardHandler {
jsonBody.put("page", pageNum);
jsonBody.put("limit", pageSize);
//开始日期结束日期
if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
if (StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate)) {
jsonBody.put("startTime", startDate);
jsonBody.put("endTime", endDate);
}
if (StringUtils.isNotBlank(customerId)) {
if (StrUtil.isNotBlank(customerId)) {
jsonBody.put("customerId", customerId);
}
if (StringUtils.isNotBlank(cardId)) {
if (StrUtil.isNotBlank(cardId)) {
jsonBody.put("cardId", cardId);
}
if (StringUtils.isNotBlank(cardType)) {
if (StrUtil.isNotBlank(cardType)) {
jsonBody.put("cardType", cardType);
}
if (cardStatus != null) {
@ -111,14 +111,14 @@ public class CloudClassCardHandler {
jsonBody.put("page", pageNum);
jsonBody.put("limit", pageSize);
//开始日期结束日期
if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
if (StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate)) {
jsonBody.put("startTime", startDate);
jsonBody.put("endTime", endDate);
}
if (StringUtils.isNotBlank(customerId)) {
if (StrUtil.isNotBlank(customerId)) {
jsonBody.put("customerId", customerId);
}
if (StringUtils.isNotBlank(cardId)) {
if (StrUtil.isNotBlank(cardId)) {
jsonBody.put("cardId", cardId);
}
//校区id

View File

@ -1,11 +1,10 @@
package com.cpop.api.cloudDb.handler;
import com.alibaba.fastjson.JSONObject;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.cpop.api.cloudDb.core.constant.CloudDbUrl;
import com.cpop.api.cloudDb.core.dto.CloudClassDto;
import com.cpop.api.cloudDb.core.dto.CloudClassStudentDto;
import com.cpop.api.cloudDb.core.dto.CloudCourseDto;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.exception.UtilException;
import com.mybatisflex.core.paginate.Page;
import org.springframework.beans.factory.annotation.Autowired;
@ -45,11 +44,11 @@ public class CloudClassHandler {
jsonBody.put("page", pageNum);
jsonBody.put("limit", pageSize);
//开始日期结束日期
if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
if (StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate)) {
jsonBody.put("startTime", startDate);
jsonBody.put("endTime", endDate);
}
if (StringUtils.isNotBlank(classId)){
if (StrUtil.isNotBlank(classId)){
jsonBody.put("classId", classId);
}
//校区id
@ -90,11 +89,11 @@ public class CloudClassHandler {
jsonBody.put("page", pageNum);
jsonBody.put("limit", pageSize);
//开始日期结束日期
if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
if (StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate)) {
jsonBody.put("startTime", startDate);
jsonBody.put("endTime", endDate);
}
if (StringUtils.isNotBlank(classId)){
if (StrUtil.isNotBlank(classId)){
jsonBody.put("classId", classId);
}
//校区id

View File

@ -1,12 +1,10 @@
package com.cpop.api.cloudDb.handler;
import com.alibaba.fastjson.JSONObject;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.cpop.api.cloudDb.core.constant.CloudDbUrl;
import com.cpop.api.cloudDb.core.dto.CloudCourseDto;
import com.cpop.api.cloudDb.core.dto.CloudCourseStudentDto;
import com.cpop.api.cloudDb.core.dto.CloudCourseStudentListDto;
import com.cpop.api.cloudDb.core.dto.CloudCustomerDto;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.exception.UtilException;
import com.mybatisflex.core.paginate.Page;
import lombok.extern.slf4j.Slf4j;
@ -14,7 +12,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
/**
@ -50,14 +47,14 @@ public class CloudCourseHandler {
jsonBody.put("page", pageNum);
jsonBody.put("limit", pageSize);
//开始日期结束日期
if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
if (StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate)) {
jsonBody.put("startTime", startDate);
jsonBody.put("endTime", endDate);
}
if (StringUtils.isNotBlank(courseId)){
if (StrUtil.isNotBlank(courseId)){
jsonBody.put("courseId", courseId);
}
if (StringUtils.isNotBlank(classId)) {
if (StrUtil.isNotBlank(classId)) {
jsonBody.put("classId", classId);
}
//校区id
@ -97,23 +94,23 @@ public class CloudCourseHandler {
JSONObject jsonBody = new JSONObject();
jsonBody.put("_type", "courseStudent");
//开始日期结束日期
if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
if (StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate)) {
jsonBody.put("startTime", startDate);
jsonBody.put("endTime", endDate);
}
if (StringUtils.isNotBlank(courseId)){
if (StrUtil.isNotBlank(courseId)){
jsonBody.put("courseId", courseId);
}
if (StringUtils.isNotBlank(customerId)){
if (StrUtil.isNotBlank(customerId)){
jsonBody.put("customerId", customerId);
}
if (StringUtils.isNotBlank(studentId)){
if (StrUtil.isNotBlank(studentId)){
jsonBody.put("studentId", studentId);
}
if (StringUtils.isNotBlank(cardId)){
if (StrUtil.isNotBlank(cardId)){
jsonBody.put("cardId", cardId);
}
if (StringUtils.isNotBlank(classId)){
if (StrUtil.isNotBlank(classId)){
jsonBody.put("classId", classId);
}
//校区id

View File

@ -1,10 +1,10 @@
package com.cpop.api.cloudDb.handler;
import com.alibaba.fastjson.JSONObject;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.cpop.api.cloudDb.core.constant.CloudDbUrl;
import com.cpop.api.cloudDb.core.dto.CloudCustomerDto;
import com.cpop.api.cloudDb.core.dto.CloudStudentDto;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.exception.UtilException;
import com.mybatisflex.core.paginate.Page;
import lombok.extern.slf4j.Slf4j;
@ -46,11 +46,11 @@ public class CloudCustomerStudentHandler {
jsonBody.put("page", pageNum);
jsonBody.put("limit", pageSize);
//开始日期结束日期
if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
if (StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate)) {
jsonBody.put("startTime", startDate);
jsonBody.put("endTime", endDate);
}
if (StringUtils.isNotBlank(customerId)){
if (StrUtil.isNotBlank(customerId)){
jsonBody.put("customerId", customerId);
}
//校区id
@ -92,14 +92,14 @@ public class CloudCustomerStudentHandler {
jsonBody.put("page", pageNum);
jsonBody.put("limit", pageSize);
//开始日期结束日期
if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
if (StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate)) {
jsonBody.put("startTime", startDate);
jsonBody.put("endTime", endDate);
}
if (StringUtils.isNotBlank(customerId)) {
if (StrUtil.isNotBlank(customerId)) {
jsonBody.put("customerId", customerId);
}
if (StringUtils.isNotBlank(studentId)) {
if (StrUtil.isNotBlank(studentId)) {
jsonBody.put("studentId", studentId);
}
//校区id

View File

@ -1,9 +1,9 @@
package com.cpop.api.cloudDb.handler;
import com.alibaba.fastjson.JSONObject;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.cpop.api.cloudDb.core.constant.CloudDbUrl;
import com.cpop.api.cloudDb.core.dto.CloudOrderDto;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.entity.ExtendPage;
import com.cpop.core.base.exception.UtilException;
import com.mybatisflex.core.paginate.Page;
@ -48,17 +48,17 @@ public class CloudOrderHandler {
jsonBody.put("page", pageNum);
jsonBody.put("limit", pageSize);
//开始日期结束日期
if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
if (StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate)) {
jsonBody.put("startTime", startDate);
jsonBody.put("endTime", endDate);
}
if (StringUtils.isNotBlank(customerId)) {
if (StrUtil.isNotBlank(customerId)) {
jsonBody.put("customerId", customerId);
}
if (StringUtils.isNotBlank(cardId)) {
if (StrUtil.isNotBlank(cardId)) {
jsonBody.put("cardId", cardId);
}
if (StringUtils.isNotBlank(orderId)) {
if (StrUtil.isNotBlank(orderId)) {
jsonBody.put("ticketId", orderId);
}
//校区id

View File

@ -1,10 +1,9 @@
package com.cpop.api.cloudDb.handler;
import com.alibaba.fastjson.JSONObject;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.cpop.api.cloudDb.core.constant.CloudDbUrl;
import com.cpop.api.cloudDb.core.dto.CloudClassDto;
import com.cpop.api.cloudDb.core.dto.CloudStaffDto;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.exception.UtilException;
import com.mybatisflex.core.paginate.Page;
import org.springframework.beans.factory.annotation.Autowired;
@ -44,11 +43,11 @@ public class CloudStaffHandler {
jsonBody.put("page", pageNum);
jsonBody.put("limit", pageSize);
//开始日期结束日期
if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
if (StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate)) {
jsonBody.put("startTime", startDate);
jsonBody.put("endTime", endDate);
}
if (StringUtils.isNotBlank(staffId)){
if (StrUtil.isNotBlank(staffId)){
jsonBody.put("staffId", staffId);
}
//校区id

View File

@ -1,10 +1,10 @@
package com.cpop.api.cloudDb.handler;
import com.alibaba.fastjson.JSONObject;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.cpop.api.cloudDb.core.constant.CloudDbUrl;
import com.cpop.api.cloudDb.core.dto.CloudStoreActiveDto;
import com.cpop.api.cloudDb.core.dto.CloudStoreDto;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.exception.UtilException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ -35,19 +35,19 @@ public class CloudStoreHandler {
jsonBody.put("_type", "storeEdit");
//云校区id
jsonBody.put("storeId", dto.getStoreCloudId());
if (StringUtils.isNotBlank(dto.getBrandCloudId())) {
if (StrUtil.isNotBlank(dto.getBrandCloudId())) {
jsonBody.put("brandId", dto.getBrandCloudId());
}
if (StringUtils.isNotBlank(dto.getStoreName())) {
if (StrUtil.isNotBlank(dto.getStoreName())) {
jsonBody.put("name", dto.getStoreName());
}
if (StringUtils.isNotBlank(dto.getPersonCharge())) {
if (StrUtil.isNotBlank(dto.getPersonCharge())) {
jsonBody.put("principalName", dto.getPersonCharge());
}
if (StringUtils.isNotBlank(dto.getPhone())) {
if (StrUtil.isNotBlank(dto.getPhone())) {
jsonBody.put("phone", dto.getPhone());
}
if (StringUtils.isNotBlank(dto.getStoreAddr())) {
if (StrUtil.isNotBlank(dto.getStoreAddr())) {
jsonBody.put("address", dto.getStoreAddr());
}
JSONObject jsonObject = restTemplate.postForObject(CloudDbUrl.COMMON_USE_URL, jsonBody, JSONObject.class);

View File

@ -1,18 +1,11 @@
package com.cpop.api.tencent.location.handler;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSONObject;
import com.cpop.api.tencent.location.core.constant.TencentApiUrl;
import com.cpop.common.utils.http.HttpUtils;
import com.cpop.core.base.exception.UtilException;
import com.cpop.core.utils.SpringUtils;
import okhttp3.Response;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
/**
* 腾讯位置服务工具类
* @author DB

View File

@ -1,6 +1,6 @@
package com.cpop.api.tencent.wxWork.core.base;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
/**

View File

@ -1,10 +1,10 @@
package com.cpop.api.tencent.wxWork.handler;
import com.alibaba.fastjson.JSONObject;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSONObject;
import com.cpop.api.tencent.wxWork.core.config.WxWorkApiConfig;
import com.cpop.api.tencent.wxWork.webHook.WebHookSendTextRequest;
import com.cpop.common.utils.http.HttpUtils;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ -39,9 +39,8 @@ public class WebHookSendHandler {
text.setContent(content);
text.setMentionedMobileList(phoneList);
request.setText(text);
Response response = HttpUtils.sendOkHttpPost(config.getWebhook() + key, JSONObject.toJSONString(request));
HttpResponse response = HttpRequest.post(config.getWebhook() + key).body(JSONObject.toJSONString(request)).execute();
response.close();
}
}

View File

@ -1,6 +1,6 @@
package com.cpop.api.tencent.wxWork.webHook;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson2.annotation.JSONField;
import com.cpop.api.tencent.wxWork.core.base.WxWorkApiWebHookSendBase;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@ -4,7 +4,7 @@
<parent>
<groupId>com.cpop</groupId>
<artifactId>Cpop-Union</artifactId>
<version>1.0.0</version>
<version>1.1.2</version>
</parent>
<artifactId>Cpop-ClockIn-Demo</artifactId>

View File

@ -1,7 +1,7 @@
package com.cpop.clockin.business.bo;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
@ -10,7 +10,7 @@ import lombok.Data;
* @Version: 1.0
*/
@Data
@ApiModel(value = "打卡记录VO")
@Schema(description = "打卡记录VO")
public class ClockInRecordBo {
@ExcelProperty(value = "姓名")
private String staffName;

View File

@ -1,7 +1,10 @@
package com.cpop.clockin.business.controller;
import com.cpop.core.base.R;
import com.cpop.core.base.entity.R;
import com.mybatisflex.core.paginate.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@ -13,9 +16,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import com.cpop.clockin.business.entity.Classes;
import com.cpop.clockin.business.service.ClassesService;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import java.io.Serializable;
import java.util.List;
@ -26,7 +26,7 @@ import java.util.List;
* @since 2024-01-23
*/
@RestController
@Api(tags = "打卡班次表接口")
@Tag(name = "打卡班次表接口")
@RequestMapping("/backstage/classes")
public class ClassesController {
@ -40,8 +40,8 @@ public class ClassesController {
* @return {@code true} 添加成功{@code false} 添加失败
*/
@PostMapping("/save")
@ApiOperation("保存打卡班次表")
public R<Void> save(@RequestBody @ApiParam("打卡班次表") Classes classes) {
@Operation(summary = "保存打卡班次表")
public R<Void> save(@RequestBody @Parameter(description = "打卡班次表") Classes classes) {
classesService.save(classes);
return R.ok();
}
@ -53,8 +53,8 @@ public class ClassesController {
* @return {@code true} 删除成功{@code false} 删除失败
*/
@DeleteMapping("/remove/{id}")
@ApiOperation("根据主键删除打卡班次表")
public R<Void> remove(@PathVariable @ApiParam("打卡班次表主键") Serializable id) {
@Operation(summary = "根据主键删除打卡班次表")
public R<Void> remove(@PathVariable @Parameter(description = "打卡班次表主键") Serializable id) {
classesService.removeById(id);
return R.ok();
}
@ -66,8 +66,8 @@ public class ClassesController {
* @return {@code true} 更新成功{@code false} 更新失败
*/
@PutMapping("/update")
@ApiOperation("根据主键更新打卡班次表")
public R<Void> update(@RequestBody @ApiParam("打卡班次表主键") Classes classes) {
@Operation(summary = "根据主键更新打卡班次表")
public R<Void> update(@RequestBody @Parameter(description = "打卡班次表主键") Classes classes) {
classesService.updateById(classes);
return R.ok();
}
@ -78,7 +78,7 @@ public class ClassesController {
* @return 所有数据
*/
@GetMapping("/list")
@ApiOperation("查询所有打卡班次表")
@Operation(summary = "查询所有打卡班次表")
public R<List<Classes>> list() {
return R.ok(classesService.list());
}
@ -90,8 +90,8 @@ public class ClassesController {
* @return 打卡班次表详情
*/
@GetMapping("/getInfo/{id}")
@ApiOperation("根据主键获取打卡班次表")
public R<Classes> getInfo(@PathVariable @ApiParam("打卡班次表主键") Serializable id) {
@Operation(summary = "根据主键获取打卡班次表")
public R<Classes> getInfo(@PathVariable @Parameter(description = "打卡班次表主键") Serializable id) {
return R.ok(classesService.getById(id));
}
@ -102,8 +102,8 @@ public class ClassesController {
* @return 分页对象
*/
@GetMapping("/page")
@ApiOperation("分页查询打卡班次表")
public R<Page<Classes>> page(@ApiParam("分页信息") Page<Classes> page) {
@Operation(summary = "分页查询打卡班次表")
public R<Page<Classes>> page(@Parameter(description = "分页信息") Page<Classes> page) {
return R.ok(classesService.page(page));
}

View File

@ -4,16 +4,16 @@ import com.alibaba.excel.EasyExcel;
import com.cpop.clockin.business.bo.EmployeeAttendanceBo;
import com.cpop.clockin.business.service.ClockInRecordService;
import com.cpop.clockin.framework.constant.ClockInConstant;
import com.cpop.core.base.R;
import com.cpop.core.base.entity.R;
import com.cpop.core.service.RedisService;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
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.IOException;
import java.net.URLEncoder;
import java.text.ParseException;
@ -27,7 +27,7 @@ import java.util.List;
* @Version: 1.0
*/
@RestController
@Api(tags = "打卡记录接口")
@Tag(name = "打卡记录接口")
@RequestMapping("/backstage/clockInRecord")
public class ClockInRecordController {
@Autowired
@ -35,7 +35,7 @@ public class ClockInRecordController {
@Autowired
private RedisService redisService;
@PostMapping("/upload")
@ApiOperation("上传钉钉Excel表")
@Operation(summary = "上传钉钉Excel表")
public R<String> uploadRecord(@RequestParam("file") MultipartFile file) throws IOException, ParseException {
/* List<ClockInRecordBo> clockInRecordBoList = ;
// 将对象数据返回给前端*/
@ -43,7 +43,7 @@ public class ClockInRecordController {
}
@GetMapping("/output")
@ApiOperation("导出表格")
@Operation(summary = "导出表格")
public void outPut(HttpServletResponse response) throws IOException {
String manTimeJson = redisService.getCacheObject(ClockInConstant.MAN_TIME_JSON);
/*byte[] bytes = manTimeJson.getBytes();

View File

@ -3,14 +3,14 @@ package com.cpop.clockin.business.controller;
import com.cpop.clockin.business.dto.StaffClassesDto;
import com.cpop.clockin.business.service.StaffClassesService;
import com.cpop.clockin.business.vo.StaffClassesVo;
import com.cpop.core.base.R;
import com.cpop.core.base.entity.R;
import com.mybatisflex.core.paginate.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import com.cpop.clockin.business.entity.StaffClasses;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import java.io.Serializable;
import java.util.List;
@ -21,7 +21,7 @@ import java.util.List;
* @since 2024-01-23
*/
@RestController
@Api(tags = "员工-班次关联表接口")
@Tag(name = "员工-班次关联表接口")
@RequestMapping("/backstage/staffClasses")
public class StaffClassesController {
@ -34,11 +34,11 @@ public class StaffClassesController {
* @author: Yxz
* @date: 2024/1/24 20:54
* @param: [staffClassesDto]
* @return: com.cpop.core.base.R<java.lang.Void>
* @return: com.cpop.core.base.entity.R<java.lang.Void>
**/
@PostMapping("/save")
@ApiOperation("保存员工-班次关联表")
public R<Void> save(@RequestBody @ApiParam("员工-班次保存Dto") StaffClassesDto staffClassesDto) {
@Operation(summary = "保存员工-班次关联表")
public R<Void> save(@RequestBody @Parameter(description = "员工-班次保存Dto") StaffClassesDto staffClassesDto) {
staffClassesService.saveAll(staffClassesDto);
return R.ok();
}
@ -50,11 +50,11 @@ public class StaffClassesController {
* @author: Yxz
* @date: 2024/1/24 20:54
* @param: [staffClassesDto]
* @return: com.cpop.core.base.R<java.lang.Void>
* @return: com.cpop.core.base.entity.R<java.lang.Void>
**/
@PutMapping("/update")
@ApiOperation("更新员工-班次关联表")
public R<Void> update(@RequestBody @ApiParam("员工-班次修改Dto") StaffClassesDto staffClassesDto) {
@Operation(summary = "更新员工-班次关联表")
public R<Void> update(@RequestBody @Parameter(description = "员工-班次修改Dto") StaffClassesDto staffClassesDto) {
staffClassesService.updateAll(staffClassesDto);
return R.ok();
}
@ -65,7 +65,7 @@ public class StaffClassesController {
* @return 所有数据
*/
@GetMapping("/list")
@ApiOperation("查询员工班次信息")
@Operation(summary = "查询员工班次信息")
public R<List<StaffClassesVo>> list() {
return R.ok(staffClassesService.getStaffClassesVolist());
}
@ -78,8 +78,8 @@ public class StaffClassesController {
* @return 员工-班次关联表详情
*/
@GetMapping("/getInfo/{id}")
@ApiOperation("根据主键获取员工-班次关联表")
public R<StaffClasses> getInfo(@PathVariable @ApiParam("员工-班次关联表主键") Serializable id) {
@Operation(summary = "根据主键获取员工-班次关联表")
public R<StaffClasses> getInfo(@PathVariable @Parameter(description = "员工-班次关联表主键") Serializable id) {
return R.ok(staffClassesService.getById(id));
}
@ -89,11 +89,11 @@ public class StaffClassesController {
* @author: Yxz
* @date: 2024/1/24 20:55
* @param: [staffName]
* @return: com.cpop.core.base.R<com.mybatisflex.core.paginate.Page<com.cpop.clockin.business.vo.StaffClassesVo>>
* @return: com.cpop.core.base.entity.R<com.mybatisflex.core.paginate.Page<com.cpop.clockin.business.vo.StaffClassesVo>>
**/
@GetMapping("/page")
@ApiOperation("分页查询员工-班次信息")
public R<Page<StaffClassesVo>> page( @ApiParam("员工名称") @RequestParam(value = "staffName", required = false)String staffName) {
@Operation(summary = "分页查询员工-班次信息")
public R<Page<StaffClassesVo>> page( @Parameter(description = "员工名称") @RequestParam(value = "staffName", required = false)String staffName) {
return R.ok(staffClassesService.selectPage(staffName));
}

View File

@ -1,7 +1,6 @@
package com.cpop.clockin.business.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
@ -10,10 +9,10 @@ import lombok.Data;
* @Version: 1.0
*/
@Data
@ApiModel(value = "员工班次DTO")
@Schema(description = "员工班次DTO")
public class StaffClassesDto {
@ApiModelProperty(value = "员工id")
@Schema(description = "员工id")
private String staffId;
@ApiModelProperty(value = "班次id数组")
@Schema(description = "班次id数组")
private String[] classId;
}

View File

@ -8,11 +8,8 @@ import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.Accessors;
@ -28,7 +25,6 @@ import lombok.experimental.Accessors;
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ApiModel(value = "打卡班次表对象")
@Table(value = "cp_oam_classes", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
public class Classes extends BaseEntity implements Serializable {
@ -38,29 +34,23 @@ public class Classes extends BaseEntity implements Serializable {
/**
* 班次名称
*/
@ApiModelProperty(value = "班次名称")
private String className;
/**
* 开始时间
*/
@ApiModelProperty(value = "开始时间")
@JsonFormat(pattern = "HH:mm:ss",timezone = "GMT+8")
private Date startTime;
/**
* 结束时间
*/
@ApiModelProperty(value = "结束时间")
@JsonFormat(pattern = "HH:mm:ss",timezone = "GMT+8")
private Date endTime;
/**
* 逻辑删除0否1是
*/
@ApiModelProperty(value = "逻辑删除0否1是")
@Column(isLogicDelete = true)
private Integer isDelete;

View File

@ -8,8 +8,6 @@ import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.Accessors;
@ -25,85 +23,68 @@ import lombok.experimental.Accessors;
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ApiModel(value = "部门表对象")
@Table(value = "cp_oam_dept", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
public class ClockInDept extends BaseEntity implements Serializable {
/**
* 部门id
*/
@ApiModelProperty(value = "部门id")
@Id
private String id;
/**
* 父部门id
*/
@ApiModelProperty(value = "父部门id")
private String parentId;
/**
* 企微id
*/
@ApiModelProperty(value = "企微id")
private Long wxCpId;
/**
* 企微父id
*/
@ApiModelProperty(value = "企微父id")
private Long wxCpParentId;
/**
* 部门名称
*/
@ApiModelProperty(value = "部门名称")
private String name;
/**
* 排序
*/
@ApiModelProperty(value = "排序")
private Integer orderNo;
/**
* 负责人
*/
@ApiModelProperty(value = "负责人")
private String leader;
/**
* 电话
*/
@ApiModelProperty(value = "电话")
private String phone;
/**
* 邮箱
*/
@ApiModelProperty(value = "邮箱")
private String email;
/**
* 部门状态:1正常,0停用
*/
@ApiModelProperty(value = "部门状态:1正常,0停用")
private Boolean status;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remark;
/**
* 逻辑删除(0否1是)
*/
@ApiModelProperty(value = "逻辑删除(0否1是)")
@Column(isLogicDelete = true)
private Boolean isDelete;

View File

@ -8,8 +8,6 @@ import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.Accessors;
@ -25,61 +23,48 @@ import lombok.experimental.Accessors;
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ApiModel(value = "员工表对象")
@Table(value = "cp_oam_staff", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
public class ClockInStaff extends BaseEntity implements Serializable {
/**
* 主键
*/
@ApiModelProperty(value = "主键")
@Id
private String id;
/**
* 姓名
*/
@ApiModelProperty(value = "姓名")
private String name;
/**
* 用户id
*/
@ApiModelProperty(value = "用户id")
private String userId;
/**
* 员工类型(0:技术人员;1:售后人员;2:管理人员)
*/
@ApiModelProperty(value = "员工类型(0:技术人员;1:售后人员;2:管理人员)")
private Integer staffType;
/**
* 角色id
*/
@ApiModelProperty(value = "角色id")
private String roleId;
/**
* 微信用userId
*/
@ApiModelProperty(value = "微信用userId")
private String wxCpUserId;
/**
* 是否是运维账号
*/
@ApiModelProperty(value = "是否是运维账号")
private Boolean isOperation;
/**
* 逻辑删除(0否1是)
*/
@ApiModelProperty(value = "逻辑删除(0否1是)")
@Column(isLogicDelete = true)
private Boolean isDelete;

View File

@ -6,8 +6,6 @@ import com.cpop.core.base.entity.BaseUpdateListener;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.Accessors;
@ -23,20 +21,17 @@ import lombok.experimental.Accessors;
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ApiModel(value = "Oam-员工-用户中间表对象")
@Table(value = "cp_oam_staff_mid_dept", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
public class ClockInStaffMidDept extends BaseEntity implements Serializable {
/**
* 员工id
*/
@ApiModelProperty(value = "员工id")
private String staffId;
/**
* 部门id
*/
@ApiModelProperty(value = "部门id")
private String deptId;

View File

@ -7,9 +7,6 @@ import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.Accessors;
@ -25,7 +22,6 @@ import lombok.experimental.Accessors;
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ApiModel(value = "员工-班次关联表对象")
@Table(value = "cp_oam_staff_classes", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
public class StaffClasses extends BaseEntity implements Serializable {
@ -35,23 +31,16 @@ public class StaffClasses extends BaseEntity implements Serializable {
/**
* 员工id
*/
@ApiModelProperty(value = "员工id")
private String staffId;
/**
* 班次id
*/
@ApiModelProperty(value = "班次id")
private String classId;
/**
* 逻辑删除0否1是
*/
@ApiModelProperty(value = "逻辑删除0否1是")
@Column(isLogicDelete = true)
private Integer isDelete;

View File

@ -4,19 +4,15 @@ import cn.hutool.core.util.ObjectUtil;
import com.cpop.clockin.business.dto.StaffClassesDto;
import com.cpop.clockin.business.entity.*;
import com.cpop.clockin.business.mapper.ClockInStaffMapper;
import com.cpop.clockin.business.mapper.StaffClassesMapper;
import com.cpop.clockin.business.service.*;
import com.cpop.clockin.business.vo.ClassesVo;
import com.cpop.clockin.business.vo.StaffClassesVo;
import com.cpop.core.base.entity.PageDomain;
import com.cpop.core.utils.SpringUtils;
import com.cpop.core.utils.sql.SqlUtils;
import com.cpop.core.utils.SqlUtils;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.DbChain;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.cpop.clockin.business.mapper.StaffClassesMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -25,8 +21,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static com.mybatisflex.core.query.QueryMethods.groupConcat;
/**
* 员工-班次关联表 服务层实现
*
@ -149,7 +143,7 @@ public class StaffClassesServiceImpl extends ServiceImpl<StaffClassesMapper, Sta
Db.paginate("cp_oam_staff",pageAs(pageDomain.getPageSize(),pageDomain.getPageSize()),
QueryWrapper.create(),)*/
Page<ClockInStaff> clockInStaffPage = clockInStaffMapper.paginate(pageDomain.getPageNum(), pageDomain.getPageSize(), QueryWrapper.create().like("name",staffName));
Page<ClockInStaff> clockInStaffPage = clockInStaffMapper.paginate(pageDomain.getPage(), pageDomain.getPageSize(), QueryWrapper.create().like("name",staffName));
List<StaffClassesVo> staffClassesVoList = clockInStaffPage.getRecords().stream().map(entity -> {
StaffClassesVo vo = new StaffClassesVo();
vo.setStaffName(entity.getName());
@ -183,7 +177,7 @@ public class StaffClassesServiceImpl extends ServiceImpl<StaffClassesMapper, Sta
}).collect(Collectors.toList());
Page<StaffClassesVo> staffClassesVoPage = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
Page<StaffClassesVo> staffClassesVoPage = new Page<>(pageDomain.getPage(), pageDomain.getPageSize());
staffClassesVoPage.setRecords(staffClassesVoList);
staffClassesVoPage.setTotalRow(clockInStaffPage.getTotalRow());
staffClassesVoPage.setTotalPage(clockInStaffPage.getTotalPage());

View File

@ -1,7 +1,6 @@
package com.cpop.clockin.business.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
@ -9,15 +8,15 @@ import lombok.Data;
* @Date: 2024/1/23 18:56
* @Version: 1.0
*/
@ApiModel(value = "班次VO")
@Schema(description = "班次VO")
@Data
public class ClassesVo {
@ApiModelProperty(value = "班次Id")
@Schema(description = "班次Id")
private String id;
/**
* 班次名称
*/
@ApiModelProperty(value = "班次名称")
@Schema(description = "班次名称")
private String className;
}

View File

@ -1,8 +1,6 @@
package com.cpop.clockin.business.vo;
import com.mybatisflex.annotation.RelationOneToMany;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@ -12,18 +10,18 @@ import java.util.List;
* @Date: 2024/1/23 17:45
* @Version: 1.0
*/
@ApiModel(value = "员工班次关联VO")
@Schema(description = "员工班次关联VO")
@Data
public class StaffClassesVo {
@ApiModelProperty("员工Id")
@Schema(description = "员工Id")
private String staffId;
@ApiModelProperty("员工名称")
@Schema(description = "员工名称")
private String staffName;
@ApiModelProperty("部门名称")
@Schema(description = "部门名称")
private String deptName;
@ApiModelProperty("考勤班次名称")
@Schema(description = "考勤班次名称")
private String className;
@ApiModelProperty("考勤班次集合")
@Schema(description = "考勤班次集合")
private List<ClassesVo> classesVoList;
}

View File

@ -1,55 +0,0 @@
<?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>com.cpop</groupId>
<artifactId>Cpop-Union</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>Cpop-Common</artifactId>
<name>Cpop-Common</name>
<description>公共包</description>
<packaging>jar</packaging>
<dependencies>
<!--常用工具类 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
</dependency>
<!--https://mvnrepository.com/artifact/commons-io/commons-io-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<!-- 时间工具类 -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!-- okhttp3 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,56 +0,0 @@
package com.cpop.common.enums;
/**
* @author DB
*/
public enum CycleEnum {
/**
*
*/
DAY(1, "每天"),
/**
*
*/
MONTH(2, ""),
/**
*
*/
WEEK(3, ""),
/**
*
*/
YEAR(4, "");
private int codeId;
private String message;
CycleEnum(int codeId, String message) {
this.codeId = codeId;
this.message = message;
}
public static CycleEnum getCycle(int code) {
for (CycleEnum c : CycleEnum.values()) {
if (c.codeId == code) {
return c;
}
}
return null;
}
public int getCodeId() {
return codeId;
}
public void setCodeId(int codeId) {
this.codeId = codeId;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@ -1,653 +0,0 @@
package com.cpop.common.utils;
import com.cpop.common.enums.CycleEnum;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
* 时间工具类
*
* @author DB
*/
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
public static String YYYY = "yyyy";
public static String YYYY_MM = "yyyy-MM";
public static String YYYY_MM_DD = "yyyy-MM-dd";
public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
public static String YYYYMMDD = "yyyyMMdd";
public static String TIME = "HH:mm:ss";
/**
* yyyy-MM-dd HH:mm
*/
public final static String DATE_TIME_HOUR_MINUTE = "yyyy-MM-dd HH:mm";
private static final String[] parsePatterns = {
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
public final static String HOUR = "HH:mm";
/**
* 获取当前Date型日期
*
* @return Date() 当前日期
*/
public static Date getNowDate() {
return new Date();
}
/**
* 获取当前日期, 默认格式为yyyy-MM-dd
*
* @return String
*/
public static String getDate() {
return dateTimeNow(YYYY_MM_DD);
}
public static String getTime() {
return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
}
public static String dateTimeNow() {
return dateTimeNow(YYYYMMDDHHMMSS);
}
public static String dateTimeNow(final String format) {
return parseDateToStr(format, new Date());
}
public static String dateTime(final Date date) {
return parseDateToStr(YYYY_MM_DD, date);
}
public static String parseDateToStr(final String format, final Date date) {
return new SimpleDateFormat(format).format(date);
}
public static Date dateTime(final String format, final String ts) {
try {
return new SimpleDateFormat(format).parse(ts);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
/**
* 日期路径 即年// 如2018/08/08
*/
public static String datePath() {
Date now = new Date();
return DateFormatUtils.format(now, "yyyy/MM/dd");
}
/**
* 日期路径 即年// 如20180808
*/
public static String dateTime() {
Date now = new Date();
return DateFormatUtils.format(now, "yyyyMMdd");
}
/**
* 日期型字符串转化为日期 格式
*/
public static Date parseDate(Object str) {
if (str == null) {
return null;
}
try {
return parseDate(str.toString(), parsePatterns);
} catch (ParseException e) {
return null;
}
}
/**
* 获取服务器启动时间
*/
public static Date getServerStartDate() {
long time = ManagementFactory.getRuntimeMXBean().getStartTime();
return new Date(time);
}
/**
* 计算两个时间差
*/
public static String getDatePoor(Date endDate, Date nowDate) {
long nd = 1000 * 24 * 60 * 60;
long nh = 1000 * 60 * 60;
long nm = 1000 * 60;
// long ns = 1000;
// 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - nowDate.getTime();
// 计算差多少天
long day = diff / nd;
// 计算差多少小时
long hour = diff % nd / nh;
// 计算差多少分钟
long min = diff % nd % nh / nm;
// 计算差多少秒//输出结果
// long sec = diff % nd % nh % nm / ns;
return day + "" + hour + "小时" + min + "分钟";
}
/**
* 对日期的进行加/
*
* @param date 日期
* @param months 月数负数为减
* @return /减几月后的日期
*/
public static Date addDateMonths(Date date, int months) {
DateTime dateTime = new DateTime(date);
return dateTime.plusMonths(months).toDate();
}
/**
* 获取指定时间前一天的时间
*
* @param date
* @return
* @Author: ZJ
*/
public static Date getLasDate(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - 1);
return calendar.getTime();
}
/**
* 对日期的进行加/
*
* @param date 日期
* @param days 天数负数为减
* @return /减几天后的日期
*/
public static Date addDateDays(Date date, int days) {
DateTime dateTime = new DateTime(date);
return dateTime.plusDays(days).toDate();
}
/**
* 对日期的小时进行加/
*
* @param date 日期
* @param hours 小时数负数为减
* @return /减几小时后的日期
*/
public static Date addDateHours(Date date, int hours) {
DateTime dateTime = new DateTime(date);
return dateTime.plusHours(hours).toDate();
}
/**
* 判断当前时间是周几
*
* @param date
* @return
*/
public static String getWeek(Date date) {
String format = DateUtils.parseDateToStr("yyyy-MM-dd", date);
DateFormat format1 = new SimpleDateFormat("yyyy-MM-dd");
Date now = null;
try {
now = format1.parse(format);
} catch (ParseException e) {
e.printStackTrace();
}
assert now != null;
Instant instant = now.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
java.time.LocalDate localDate = instant.atZone(zoneId).toLocalDate();
DayOfWeek day = localDate.getDayOfWeek();
String WeekDay = "";
switch (day) {
case MONDAY:
WeekDay = "1";
break;
case FRIDAY:
WeekDay = "5";
break;
case SATURDAY:
WeekDay = "6";
break;
case SUNDAY:
WeekDay = "7";
break;
case THURSDAY:
WeekDay = "4";
break;
case TUESDAY:
WeekDay = "2";
break;
case WEDNESDAY:
WeekDay = "3";
break;
}
return WeekDay;
}
/**
* 获取指定时间前一个月的时间
*
* @param date 指定时间如果传空为当前时间
* @return
* @Author: 李性禄
*/
public static Date getLastMon(Date date) {
Calendar calendar = Calendar.getInstance();
if (date != null) {
calendar.setTime(date);
}
calendar.add(Calendar.MONTH, -1);
return calendar.getTime();
}
/**
* 获取指定时间前一年的时间
*
* @param date 指定时间如果传空为当前时间
* @return
* @Author: 李性禄
*/
public static Date getLastYear(Date date) {
Calendar calendar = Calendar.getInstance();
if (date != null) {
calendar.setTime(date);
}
calendar.add(Calendar.YEAR, -1);
return calendar.getTime();
}
/**
* 传入两个时间比较两个时间相差年
*
* @param startDate
* @param endxDate
* @return
*/
public static List<String> getTimeList(String startDate, String endxDate) {
SimpleDateFormat sdf;
int calendarType;
switch (startDate.length()) {
case 10:
sdf = new SimpleDateFormat("yyyy-MM-dd");
calendarType = Calendar.DATE;
break;
case 7:
sdf = new SimpleDateFormat("yyyy-MM");
calendarType = Calendar.MONTH;
break;
case 4:
sdf = new SimpleDateFormat("yyyy");
calendarType = Calendar.YEAR;
break;
default:
return null;
}
List<String> result = new ArrayList<>();
Calendar min = Calendar.getInstance();
Calendar max = Calendar.getInstance();
try {
min.setTime(sdf.parse(startDate));
min.add(calendarType, 0);
max.setTime(sdf.parse(endxDate));
max.add(calendarType, 1);
} catch (ParseException e) {
e.printStackTrace();
}
Calendar curr = min;
while (curr.before(max)) {
result.add(sdf.format(min.getTime()));
curr.add(calendarType, 1);
}
return result;
}
/**
* 日期转换字符串
*
* @param date
* @param pattern 转换的类型
* @return
*/
public static String format(Date date, String pattern) {
if (date != null) {
SimpleDateFormat df = new SimpleDateFormat(pattern);
return df.format(date);
}
return null;
}
/**
* 根据相差毫秒值查询相差多少天
*
* @param result
* @return
*/
public static long days(long result) {
return result / (1000 * 60 * 60 * 24);
}
/**
* 根据相差毫秒值查询相差多少个钟
*
* @param result
* @return
*/
public static long hour(long result) {
return (result % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60);
}
/**
* 根据相差毫秒值查询相差多少分钟
*
* @param result
* @return
*/
public static long minutes(long result) {
return (result % (1000 * 60 * 60)) / (1000 * 60);
}
/**
* 字符串转换成日期
*
* @param strDate 日期字符串
* @param pattern 日期的格式DateUtils.DATE_TIME_PATTERN
*/
public static Date stringToDate(String strDate, String pattern) {
if (StringUtils.isBlank(strDate)) {
return null;
}
DateTimeFormatter fmt = DateTimeFormat.forPattern(pattern);
return fmt.parseLocalDateTime(strDate).toDate();
}
/**
* 根据传入的时间获取当前月份的所有日期
*
* @param date
* @return
*/
public static List<Date> getAllTheDateOfTheMonth(Date date) {
List<Date> list = new ArrayList<Date>();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.DATE, 1);
int month = cal.get(Calendar.MONTH);
while (cal.get(Calendar.MONTH) == month) {
list.add(cal.getTime());
cal.add(Calendar.DAY_OF_YEAR, 1);
}
return list;
}
/**
* 根据传入的时间获取是当月的第几天
*
* @param date
* @return
*/
public static Integer dayOfMonth(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal.get(Calendar.DAY_OF_MONTH);
}
/**
* 根据当前时间yyyyMMdd 格式判断是否是节假日私人api慎用容易服务挂掉
*
* @param date 请求参数
* @return 返回结果 默认返回 0工作1-5 1周末 2节假日
*/
public static String holidays(String date) {
String httpUrl = "http://tool.bitefu.net/jiari/";
BufferedReader reader = null;
String holidays = null;
StringBuffer sbf = new StringBuffer();
httpUrl = httpUrl + "?d=" + date;
try {
URL url = new URL(httpUrl);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setRequestMethod("GET");
connection.connect();
InputStream is = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String strRead = null;
while ((strRead = reader.readLine()) != null) {
sbf.append(strRead);
}
reader.close();
holidays = sbf.toString();
} catch (Exception e) {
e.printStackTrace();
}
return holidays;
}
/**
* 获取两个时间之前的日期
*
* @return
*/
public static List<String> getDatesBetweenTwoDatesForApprove(Date startTime, Date endTime) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String date1 = sdf.format(startTime);
String date2 = sdf.format(endTime);
List<String> dateList = new ArrayList<String>();
try {
Date dateOne = sdf.parse(date1);
Date dateTwo = sdf.parse(date2);
Calendar calendar = Calendar.getInstance();
calendar.setTime(dateOne);
dateList.add(sdf.format(dateOne));
while (calendar.getTime().before(dateTwo)) {
calendar.add(Calendar.DAY_OF_MONTH, +1);
dateList.add(sdf.format(calendar.getTime()));
}
} catch (Exception e) {
e.printStackTrace();
}
return dateList;
}
/**
* 计算两个时间是否为同一周期
*
* @param d1 时间1
* @param d2 时间2
* @param type 周期类型
*/
public static Boolean sameCycle(Date d1, Date d2, int type) {
CycleEnum cycle = CycleEnum.getCycle(type);
assert cycle != null;
if (cycle.equals(CycleEnum.YEAR)) {
return isSameYear(d1, d2);
} else if (cycle.equals(CycleEnum.MONTH)) {
return isSameMonth(d1, d2);
} else if (cycle.equals(CycleEnum.WEEK)) {
return isSameWeek(d1, d2);
} else if (cycle.equals(CycleEnum.DAY)) {
return isSameDate(d1, d2);
}
return false;
}
/**
* 同一年
*
* @param date1
* @param date2
*/
public static Boolean isSameYear(Date date1, Date date2) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);
}
/**
* 同一月
*
* @param date1
* @param date2
* @return
*/
public static Boolean isSameMonth(Date date1, Date date2) {
if (!isSameYear(date1, date2)) {
return false;
}
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
return cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH);
}
/**
* 同一周
*
* @param date1
* @param date2
* @return
*/
public static Boolean isSameWeek(Date date1, Date date2) {
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
//西方周日为一周的第一天咱得将周一设为一周第一天
cal1.setFirstDayOfWeek(Calendar.MONDAY);
cal1.setTime(date1);
cal2.setTime(date2);
return cal1.get(Calendar.WEEK_OF_YEAR) == cal2.get(Calendar.WEEK_OF_YEAR);
}
/**
* 同一天
*
* @param date1
* @param date2
* @return
*/
public static Boolean isSameDate(Date date1, Date date2) {
if (!isSameMonth(date1, date2)) {
return false;
}
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
return cal1.get(Calendar.DAY_OF_MONTH) == cal2.get(Calendar.DAY_OF_MONTH);
}
/**
* 查看两个时间之间的日期(包含结束那一天)
*
* @param startTime
* @param endTime
* @return
*/
public static List<String> getDatesBetweenTwoDatesT(Date startTime, Date endTime) {
List<String> days = new ArrayList<>();
Calendar startCal = Calendar.getInstance();
startCal.setTime(startTime);
Calendar endCal = Calendar.getInstance();
endCal.setTime(endTime);
endCal.add(Calendar.DATE, 1);
while (startCal.before(endCal)) {
days.add(DateUtils.format(startCal.getTime(), DateUtils.YYYY_MM_DD));
startCal.add(Calendar.DAY_OF_YEAR, 1);
}
return days;
}
/**
* 获取指定时间内所有时间所有天数转为字符串集合
*
* @param startTime 开始时间
* * @param endTime 结束时间
* *@Author: 李性禄
* @return
*/
public static List<String> getDateList(Date startTime, Date endTime, String format) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
List<String> list = new ArrayList<>();
list.add(simpleDateFormat.format(startTime));
String endDay = simpleDateFormat.format(endTime);
String end = null;
Date date = startTime;
while (!endDay.equals(end)) {
if ("yyyy-MM-dd".equals(format)) {
date = getLasDate(date);
}
if ("yyyy-MM".equals(format)) {
date = getLastMon(date);
}
end = simpleDateFormat.format(date);
list.add(end);
}
return list;
}
public static String setTime(Date date) {
long millis = System.currentTimeMillis();
String endTim = "";
if (date != null) {
long time = date.getTime();
long end = (millis - time) / 1000;
if (end < 60L) {
endTim = end + "秒前";
} else if (end < 3600L) {
endTim = (end / 60) + "分前";
} else if (end < (long) (60 * 60 * 24)) {
endTim = (end / (60 * 60)) + "小时前";
} else if (end < (long) (60 * 60 * 24 * 30)) {
endTim = (end / (60 * 60 * 24)) + "天前";
} else if (end < (long) (60 * 60 * 24 * 30 * 12)) {
endTim = (end / (60 * 60 * 24)) + "月前";
} else {
endTim = (end / (60 * 60 * 24 * 30 * 12)) + "年前";
}
}
return endTim;
}
}

View File

@ -1,29 +0,0 @@
package com.cpop.common.utils;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public class JsonUtils {
private static final ObjectMapper JSON = new ObjectMapper();
static {
JSON.setSerializationInclusion(Include.NON_NULL);
JSON.configure(SerializationFeature.INDENT_OUTPUT, Boolean.TRUE);
}
public static String toJson(Object obj) {
try {
return JSON.writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -1,562 +0,0 @@
package com.cpop.common.utils;
import com.cpop.common.constant.Constants;
import com.cpop.common.utils.text.StrFormatter;
import org.springframework.util.AntPathMatcher;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
* 字符串工具类
*
* @author DB
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils {
/**
* 空字符串
*/
private static final String NULL_STR = "";
/**
* 下划线
*/
private static final char SEPARATOR = '_';
/**
* 获取参数不为空值
*
* @param value defaultValue 要判断的value
* @return value 返回值
*/
public static <T> T nvl(T value, T defaultValue) {
return value != null ? value : defaultValue;
}
/**
* * 判断一个Collection是否为空 包含ListSetQueue
*
* @param coll 要判断的Collection
* @return true为空 false非空
*/
public static boolean isEmpty(Collection<?> coll) {
return isNull(coll) || coll.isEmpty();
}
/**
* * 判断一个Collection是否非空包含ListSetQueue
*
* @param coll 要判断的Collection
* @return true非空 false
*/
public static boolean isNotEmpty(Collection<?> coll) {
return !isEmpty(coll);
}
/**
* * 判断一个对象数组是否为空
*
* @param objects 要判断的对象数组
* * @return true为空 false非空
*/
public static boolean isEmpty(Object[] objects) {
return isNull(objects) || (objects.length == 0);
}
/**
* * 判断一个对象数组是否非空
*
* @param objects 要判断的对象数组
* @return true非空 false
*/
public static boolean isNotEmpty(Object[] objects) {
return !isEmpty(objects);
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true为空 false非空
*/
public static boolean isEmpty(Map<?, ?> map) {
return isNull(map) || map.isEmpty();
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true非空 false
*/
public static boolean isNotEmpty(Map<?, ?> map) {
return !isEmpty(map);
}
/**
* * 判断一个字符串是否为空串
*
* @param str String
* @return true为空 false非空
*/
public static boolean isEmpty(String str) {
return isNull(str) || NULL_STR.equals(str.trim());
}
/**
* * 判断一个字符串是否为非空串
*
* @param str String
* @return true非空串 false空串
*/
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
/**
* * 判断一个对象是否为空
*
* @param object Object
* @return true为空 false非空
*/
public static boolean isNull(Object object) {
return object == null;
}
/**
* * 判断一个对象是否非空
*
* @param object Object
* @return true非空 false
*/
public static boolean isNotNull(Object object) {
return !isNull(object);
}
/**
* * 判断一个对象是否是数组类型Java基本型别的数组
*
* @param object 对象
* @return true是数组 false不是数组
*/
public static boolean isArray(Object object) {
return isNotNull(object) && object.getClass().isArray();
}
/**
* 去空格
*/
public static String trim(String str) {
return (str == null ? "" : str.trim());
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @return 结果
*/
public static String substring(final String str, int start) {
if (str == null) {
return NULL_STR;
}
if (start < 0) {
start = str.length() + start;
}
if (start < 0) {
start = 0;
}
if (start > str.length()) {
return NULL_STR;
}
return str.substring(start);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @param end 结束
* @return 结果
*/
public static String substring(final String str, int start, int end) {
if (str == null) {
return NULL_STR;
}
if (end < 0) {
end = str.length() + end;
}
if (start < 0) {
start = str.length() + start;
}
if (end > str.length()) {
end = str.length();
}
if (start > end) {
return NULL_STR;
}
if (start < 0) {
start = 0;
}
if (end < 0) {
end = 0;
}
return str.substring(start, end);
}
/**
* 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* <br>
* 通常使用format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{} format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\ format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param template 文本模板被替换的部分用 {} 表示
* @param params 参数值
* @return 格式化后的文本
*/
public static String format(String template, Object... params) {
if (isEmpty(params) || isEmpty(template)) {
return template;
}
return StrFormatter.format(template, params);
}
/**
* 是否为http(s)://开头
*
* @param link 链接
* @return 结果
*/
public static boolean isHttp(String link) {
return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
}
/**
* 字符串转set
*
* @param str 字符串
* @param sep 分隔符
* @return set集合
*/
public static Set<String> str2Set(String str, String sep) {
return new HashSet<String>(str2List(str, sep, true, false));
}
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @param filterBlank 过滤纯空白
* @param trim 去掉首尾空白
* @return list集合
*/
public static List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) {
List<String> list = new ArrayList<String>();
if (StringUtils.isEmpty(str)) {
return list;
}
// 过滤空白字符串
if (filterBlank && StringUtils.isBlank(str)) {
return list;
}
String[] split = str.split(sep);
for (String string : split) {
if (filterBlank && StringUtils.isBlank(string)) {
continue;
}
if (trim) {
string = string.trim();
}
list.add(string);
}
return list;
}
/**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
*
* @param cs 指定字符串
* @param searchCharSequences 需要检查的字符串数组
* @return 是否包含任意一个字符串
*/
public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) {
if (isEmpty(cs) || isEmpty(searchCharSequences)) {
return false;
}
for (CharSequence testStr : searchCharSequences) {
if (containsIgnoreCase(cs, testStr)) {
return true;
}
}
return false;
}
/**
* 驼峰转下划线命名
*/
public static String toUnderScoreCase(String str) {
if (str == null) {
return null;
}
StringBuilder sb = new StringBuilder();
// 前置字符是否大写
boolean preCharIsUpperCase = true;
// 当前字符是否大写
boolean curreCharIsUpperCase = true;
// 下一字符是否大写
boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (i > 0) {
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
} else {
preCharIsUpperCase = false;
}
curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1)) {
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
sb.append(SEPARATOR);
} else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
}
return sb.toString();
}
/**
* 是否包含字符串
*
* @param str 验证字符串
* @param strs 字符串组
* @return 包含返回true
*/
public static boolean inStringIgnoreCase(String str, String... strs) {
if (str != null && strs != null) {
for (String s : strs) {
if (str.equalsIgnoreCase(trim(s))) {
return true;
}
}
}
return false;
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式如果转换前的下划线大写方式命名的字符串为空则返回空字符串 例如HELLO_WORLD->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String convertToCamelCase(String name) {
StringBuilder result = new StringBuilder();
// 快速检查
if (name == null || name.isEmpty()) {
// 没必要转换
return "";
} else if (!name.contains("_")) {
// 不含下划线仅将首字母大写
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
// 用下划线将原始字符串分割
String[] camels = name.split("_");
for (String camel : camels) {
// 跳过原始字符串中开头结尾的下换线或双重下划线
if (camel.isEmpty()) {
continue;
}
// 首字母大写
result.append(camel.substring(0, 1).toUpperCase());
result.append(camel.substring(1).toLowerCase());
}
return result.toString();
}
/**
* 驼峰式命名法 例如user_name->userName
*/
public static String toCamelCase(String s) {
if (s == null) {
return null;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == SEPARATOR) {
upperCase = true;
} else if (upperCase) {
sb.append(Character.toUpperCase(c));
upperCase = false;
} else {
sb.append(c);
}
}
return sb.toString();
}
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strs) {
if (isEmpty(str) || isEmpty(strs)) {
return false;
}
for (String pattern : strs) {
if (isMatch(pattern, str)) {
return true;
}
}
return false;
}
/**
* 判断url是否与规则配置:
* ? 表示单个字符;
* * 表示一层路径内的任意字符串不可跨层级;
* ** 表示任意层路径;
*
* @param pattern 匹配规则
* @param url 需要匹配的url
* @return
*/
public static boolean isMatch(String pattern, String url) {
AntPathMatcher matcher = new AntPathMatcher();
return matcher.match(pattern, url);
}
@SuppressWarnings("unchecked")
public static <T> T cast(Object obj) {
return (T) obj;
}
/**
* 首字母大写(进行字母的ascii编码前移效率是最高的)
*
* @param fieldName 需要转化的字符串
*/
public static String getMethodName(String fieldName) {
char[] chars = fieldName.toCharArray();
chars[0] = toUpperCase(chars[0]);
return String.valueOf(chars);
}
/**
* 字符转成大写
*
* @param c 需要转化的字符
*/
public static char toUpperCase(char c) {
if (97 <= c && c <= 122) {
c ^= 32;
}
return c;
}
/**
* 数字左边补齐0使之达到指定长度注意如果数字转换为字符串后长度大于size则只保留 最后size个字符
*
* @param num 数字对象
* @param size 字符串指定长度
* @return 返回数字的字符串格式该字符串为指定长度
*/
public static String padL(final Number num, final int size)
{
return padL(num.toString(), size, '0');
}
/**
* 字符串左补齐如果原始字符串s长度大于size则只保留最后size个字符
*
* @param s 原始字符串
* @param size 字符串指定长度
* @param c 用于补齐的字符
* @return 返回指定长度的字符串由原字符串左补齐或截取得到
*/
public static String padL(final String s, final int size, final char c)
{
final StringBuilder sb = new StringBuilder(size);
if (s != null)
{
final int len = s.length();
if (s.length() <= size)
{
for (int i = size - len; i > 0; i--)
{
sb.append(c);
}
sb.append(s);
}
else
{
return s.substring(len - size, len);
}
}
else
{
for (int i = size; i > 0; i--)
{
sb.append(c);
}
}
return sb.toString();
}
/**
*
* @param aString 要截取的字符串
* @param startIndex 开始下标
* @param endIndex 截取长度
*/
public static String substringByte(String aString,int startIndex,int endIndex) {
byte[] bytes = aString.getBytes(StandardCharsets.UTF_8);
int subLen = endIndex - startIndex;
if (startIndex < 0) {
return "startIndex异常";
}
if (endIndex > bytes.length) {
return "endIndex异常";
}
if (subLen <= 0) {
return "startIndex或endIndex异常";
}
byte[] subBytes = new byte[subLen];
int i = 0;
while (startIndex < endIndex) {
subBytes[i++] = bytes[startIndex++];
}
return new String(subBytes, StandardCharsets.UTF_8);
}
}

View File

@ -1,193 +0,0 @@
package com.cpop.common.utils.bean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Bean 工具类
*
* @author DB
*/
public class BeanUtils extends org.springframework.beans.BeanUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(BeanUtils.class);
/**
* Bean方法名中属性名开始的下标
*/
private static final int BEAN_METHOD_PROP_INDEX = 3;
/**
* 匹配getter方法的正则表达式
*/
private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)");
/**
* 匹配setter方法的正则表达式
*/
private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)");
/**
* Bean属性复制工具方法
*
* @param dest 目标对象
* @param src 源对象
*/
public static void copyBeanProp(Object dest, Object src) {
try {
copyProperties(src, dest);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 实体类转换
* @param source 资源
* @param target 目标
* @param <T> 目标类型
* @return 转换结果
*/
public static <T> T sourceToTarget(Object source, Class<T> target){
if(source == null){
return null;
}
T targetObject = null;
try {
targetObject = target.newInstance();
BeanUtils.copyProperties(source, targetObject);
} catch (Exception e) {
LOGGER.error("实体类转换失败: ", e);
}
return targetObject;
}
/**
* 获取对象的setter方法
*
* @param obj 对象
* @return 对象的setter方法列表
*/
public static List<Method> getSetterMethods(Object obj) {
// setter方法列表
List<Method> setterMethods = new ArrayList<Method>();
// 获取所有方法
Method[] methods = obj.getClass().getMethods();
// 查找setter方法
for (Method method : methods) {
Matcher m = SET_PATTERN.matcher(method.getName());
if (m.matches() && (method.getParameterTypes().length == 1)) {
setterMethods.add(method);
}
}
// 返回setter方法列表
return setterMethods;
}
/**
* 获取对象的getter方法
*
* @param obj 对象
* @return 对象的getter方法列表
*/
public static List<Method> getGetterMethods(Object obj) {
// getter方法列表
List<Method> getterMethods = new ArrayList<Method>();
// 获取所有方法
Method[] methods = obj.getClass().getMethods();
// 查找getter方法
for (Method method : methods) {
Matcher m = GET_PATTERN.matcher(method.getName());
if (m.matches() && (method.getParameterTypes().length == 0)) {
getterMethods.add(method);
}
}
// 返回getter方法列表
return getterMethods;
}
/**
* 检查Bean方法名中的属性名是否相等<br>
* 如getName()和setName()属性名一样getName()和setAge()属性名不一样
*
* @param m1 方法名1
* @param m2 方法名2
* @return 属性名一样返回true否则返回false
*/
public static boolean isMethodPropEquals(String m1, String m2) {
return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX));
}
/**
* 对象转换
*
* @param sourceObject 原Object
* @param destinationClass 转换class
* @param <T> 转换实体类
* @param <E> 原实体类
* @return T
*/
public static <T, E> T mapToClass(E sourceObject, Class<T> destinationClass) {
T targetObject = instantiateClass(destinationClass);
copyProperties(sourceObject, targetObject);
return targetObject;
}
/**
* List转换
*
* @param sourceList 原List
* @param destinationClass 转换class
* @param <T> 转换实体类
* @param <E> 原实体类
* @return List<T>
*/
public static <T, E> List<T> mapToList(List<E> sourceList, Class<T> destinationClass) {
List<T> destinationList = new ArrayList<>(sourceList.size());
for (E sourceObject : sourceList) {
T targetObject = instantiateClass(destinationClass);
copyProperties(sourceObject, targetObject);
destinationList.add(targetObject);
}
return destinationList;
}
/**
* @param origin
* @param t
* @author LOST.yuan
* @Description map转对象
* @date 11:52 2022/8/23
**/
public static <T> void mapToObj(Map<String, String> origin, T t) {
Class<?> clazz = t.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
Object o = origin.get(fieldName);
if (o == null) {
continue;
}
String value = o.toString();
try {
field.set(t, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}

View File

@ -1,134 +0,0 @@
package com.cpop.common.utils.html;
import com.cpop.common.utils.StringUtils;
/**
* 转义和反转义工具类
*
* @author DB
*/
public class EscapeUtil {
public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)";
private static final char[][] TEXT = new char[64][];
static {
for (int i = 0; i < 64; i++) {
TEXT[i] = new char[]{(char) i};
}
// special HTML characters
// 单引号
TEXT['\''] = "&#039;".toCharArray();
// 双引号
TEXT['"'] = "&#34;".toCharArray();
// &
TEXT['&'] = "&#38;".toCharArray();
// 小于号
TEXT['<'] = "&#60;".toCharArray();
// 大于号
TEXT['>'] = "&#62;".toCharArray();
}
/**
* 转义文本中的HTML字符为安全的字符
*
* @param text 被转义的文本
* @return 转义后的文本
*/
public static String escape(String text) {
return encode(text);
}
/**
* 还原被转义的HTML特殊字符
*
* @param content 包含转义符的HTML内容
* @return 转换后的字符串
*/
public static String unescape(String content) {
return decode(content);
}
/**
* 清除所有HTML标签但是不删除标签内的内容
*
* @param content 文本
* @return 清除标签后的文本
*/
public static String clean(String content) {
return new HTMLFilter().filter(content);
}
/**
* Escape编码
*
* @param text 被编码的文本
* @return 编码后的字符
*/
private static String encode(String text) {
if (StringUtils.isEmpty(text)) {
return StringUtils.EMPTY;
}
final StringBuilder tmp = new StringBuilder(text.length() * 6);
char c;
for (int i = 0; i < text.length(); i++) {
c = text.charAt(i);
if (c < 256) {
tmp.append("%");
if (c < 16) {
tmp.append("0");
}
tmp.append(Integer.toString(c, 16));
} else {
tmp.append("%u");
if (c <= 0xfff) {
// issue#I49JU8@Gitee
tmp.append("0");
}
tmp.append(Integer.toString(c, 16));
}
}
return tmp.toString();
}
/**
* Escape解码
*
* @param content 被转义的内容
* @return 解码后的字符串
*/
public static String decode(String content) {
if (StringUtils.isEmpty(content)) {
return content;
}
StringBuilder tmp = new StringBuilder(content.length());
int lastPos = 0, pos = 0;
char ch;
while (lastPos < content.length()) {
pos = content.indexOf("%", lastPos);
if (pos == lastPos) {
if (content.charAt(pos + 1) == 'u') {
ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16);
tmp.append(ch);
lastPos = pos + 6;
} else {
ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16);
tmp.append(ch);
lastPos = pos + 3;
}
} else {
if (pos == -1) {
tmp.append(content.substring(lastPos));
lastPos = content.length();
} else {
tmp.append(content.substring(lastPos, pos));
lastPos = pos;
}
}
}
return tmp.toString();
}
}

View File

@ -1,499 +0,0 @@
package com.cpop.common.utils.html;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* HTML过滤器用于去除XSS漏洞隐患
*
* @author DB
*/
public final class HTMLFilter {
/**
* regex flag union representing /si modifiers in php
**/
private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
private static final Pattern P_END_ARROW = Pattern.compile("^>");
private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
private static final Pattern P_AMP = Pattern.compile("&");
private static final Pattern P_QUOTE = Pattern.compile("\"");
private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
// @xxx could grow large... maybe use sesat's ReferenceMap
private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>();
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>();
/**
* set of allowed html elements, along with allowed attributes for each element
**/
private final Map<String, List<String>> vAllowed;
/**
* counts of open tags for each (allowable) html element
**/
private final Map<String, Integer> vTagCounts = new HashMap<>();
/**
* html elements which must always be self-closing (e.g. "<img />")
**/
private final String[] vSelfClosingTags;
/**
* html elements which must always have separate opening and closing tags (e.g. "<b></b>")
**/
private final String[] vNeedClosingTags;
/**
* set of disallowed html elements
**/
private final String[] vDisallowed;
/**
* attributes which should be checked for valid protocols
**/
private final String[] vProtocolAtts;
/**
* allowed protocols
**/
private final String[] vAllowedProtocols;
/**
* tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
**/
private final String[] vRemoveBlanks;
/**
* entities allowed within html markup
**/
private final String[] vAllowedEntities;
/**
* flag determining whether comments are allowed in input String.
*/
private final boolean stripComment;
private final boolean encodeQuotes;
/**
* flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "<b text </b>"
* becomes "<b> text </b>"). If set to false, unbalanced angle brackets will be html escaped.
*/
private final boolean alwaysMakeTags;
/**
* Default constructor.
*/
public HTMLFilter() {
vAllowed = new HashMap<>();
final ArrayList<String> a_atts = new ArrayList<>();
a_atts.add("href");
a_atts.add("target");
vAllowed.put("a", a_atts);
final ArrayList<String> img_atts = new ArrayList<>();
img_atts.add("src");
img_atts.add("width");
img_atts.add("height");
img_atts.add("alt");
vAllowed.put("img", img_atts);
final ArrayList<String> no_atts = new ArrayList<>();
vAllowed.put("b", no_atts);
vAllowed.put("strong", no_atts);
vAllowed.put("i", no_atts);
vAllowed.put("em", no_atts);
vSelfClosingTags = new String[]{"img"};
vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
vDisallowed = new String[]{};
// no ftp.
vAllowedProtocols = new String[]{"http", "mailto", "https"};
vProtocolAtts = new String[]{"src", "href"};
vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
stripComment = true;
encodeQuotes = true;
alwaysMakeTags = false;
}
/**
* Map-parameter configurable constructor.
*
* @param conf map containing configuration. keys match field names.
*/
@SuppressWarnings("unchecked")
public HTMLFilter(final Map<String, Object> conf) {
assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
vDisallowed = (String[]) conf.get("vDisallowed");
vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
vProtocolAtts = (String[]) conf.get("vProtocolAtts");
vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
vAllowedEntities = (String[]) conf.get("vAllowedEntities");
stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
}
private void reset() {
vTagCounts.clear();
}
// ---------------------------------------------------------------
// my versions of some PHP library functions
public static String chr(final int decimal) {
return String.valueOf((char) decimal);
}
public static String htmlSpecialChars(final String s) {
String result = s;
result = regexReplace(P_AMP, "&amp;", result);
result = regexReplace(P_QUOTE, "&quot;", result);
result = regexReplace(P_LEFT_ARROW, "&lt;", result);
result = regexReplace(P_RIGHT_ARROW, "&gt;", result);
return result;
}
// ---------------------------------------------------------------
/**
* given a user submitted input String, filter out any invalid or restricted html.
*
* @param input text (i.e. submitted by a user) than may contain html
* @return "clean" version of input, with only valid, whitelisted html elements allowed
*/
public String filter(final String input) {
reset();
String s = input;
s = escapeComments(s);
s = balanceHTML(s);
s = checkTags(s);
s = processRemoveBlanks(s);
// s = validateEntities(s);
return s;
}
public boolean isAlwaysMakeTags() {
return alwaysMakeTags;
}
public boolean isStripComments() {
return stripComment;
}
private String escapeComments(final String s) {
final Matcher m = P_COMMENTS.matcher(s);
final StringBuffer buf = new StringBuffer();
if (m.find()) {
// (.*?)
final String match = m.group(1);
m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
}
m.appendTail(buf);
return buf.toString();
}
private String balanceHTML(String s) {
if (alwaysMakeTags) {
//
// try and form html
//
s = regexReplace(P_END_ARROW, "", s);
// 不追加结束标签
s = regexReplace(P_BODY_TO_END, "<$1>", s);
s = regexReplace(P_XML_CONTENT, "$1<$2", s);
} else {
//
// escape stray brackets
//
s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s);
//
// the last regexp causes '<>' entities to appear
// (we need to do a lookahead assertion so that the last bracket can
// be used in the next pass of the regexp)
//
s = regexReplace(P_BOTH_ARROWS, "", s);
}
return s;
}
private String checkTags(String s) {
Matcher m = P_TAGS.matcher(s);
final StringBuffer buf = new StringBuffer();
while (m.find()) {
String replaceStr = m.group(1);
replaceStr = processTag(replaceStr);
m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
}
m.appendTail(buf);
// these get tallied in processTag
// (remember to reset before subsequent calls to filter method)
final StringBuilder sBuilder = new StringBuilder(buf.toString());
for (String key : vTagCounts.keySet()) {
for (int ii = 0; ii < vTagCounts.get(key); ii++) {
sBuilder.append("</").append(key).append(">");
}
}
s = sBuilder.toString();
return s;
}
private String processRemoveBlanks(final String s) {
String result = s;
for (String tag : vRemoveBlanks) {
if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) {
P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
}
result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) {
P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
}
result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
}
return result;
}
private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) {
Matcher m = regex_pattern.matcher(s);
return m.replaceAll(replacement);
}
private String processTag(final String s) {
// ending tags
Matcher m = P_END_TAG.matcher(s);
if (m.find()) {
final String name = m.group(1).toLowerCase();
if (allowed(name)) {
if (!inArray(name, vSelfClosingTags)) {
if (vTagCounts.containsKey(name)) {
vTagCounts.put(name, vTagCounts.get(name) - 1);
return "</" + name + ">";
}
}
}
}
// starting tags
m = P_START_TAG.matcher(s);
if (m.find()) {
final String name = m.group(1).toLowerCase();
final String body = m.group(2);
String ending = m.group(3);
// debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
if (allowed(name)) {
final StringBuilder params = new StringBuilder();
final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
final List<String> paramNames = new ArrayList<>();
final List<String> paramValues = new ArrayList<>();
while (m2.find()) {
paramNames.add(m2.group(1)); // ([a-z0-9]+)
paramValues.add(m2.group(3)); // (.*?)
}
while (m3.find()) {
paramNames.add(m3.group(1)); // ([a-z0-9]+)
paramValues.add(m3.group(3)); // ([^\"\\s']+)
}
String paramName, paramValue;
for (int ii = 0; ii < paramNames.size(); ii++) {
paramName = paramNames.get(ii).toLowerCase();
paramValue = paramValues.get(ii);
// debug( "paramName='" + paramName + "'" );
// debug( "paramValue='" + paramValue + "'" );
// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
if (allowedAttribute(name, paramName)) {
if (inArray(paramName, vProtocolAtts)) {
paramValue = processParamProtocol(paramValue);
}
params.append(' ').append(paramName).append("=\\\"").append(paramValue).append("\"");
}
}
if (inArray(name, vSelfClosingTags)) {
ending = " /";
}
if (inArray(name, vNeedClosingTags)) {
ending = "";
}
if (ending == null || ending.length() < 1) {
if (vTagCounts.containsKey(name)) {
vTagCounts.put(name, vTagCounts.get(name) + 1);
} else {
vTagCounts.put(name, 1);
}
} else {
ending = " /";
}
return "<" + name + params + ending + ">";
} else {
return "";
}
}
// comments
m = P_COMMENT.matcher(s);
if (!stripComment && m.find()) {
return "<" + m.group() + ">";
}
return "";
}
private String processParamProtocol(String s) {
s = decodeEntities(s);
final Matcher m = P_PROTOCOL.matcher(s);
if (m.find()) {
final String protocol = m.group(1);
if (!inArray(protocol, vAllowedProtocols)) {
// bad protocol, turn into local anchor link instead
s = "#" + s.substring(protocol.length() + 1);
if (s.startsWith("#//")) {
s = "#" + s.substring(3);
}
}
}
return s;
}
private String decodeEntities(String s) {
StringBuffer buf = new StringBuffer();
Matcher m = P_ENTITY.matcher(s);
while (m.find()) {
final String match = m.group(1);
final int decimal = Integer.decode(match);
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString();
buf = new StringBuffer();
m = P_ENTITY_UNICODE.matcher(s);
while (m.find()) {
final String match = m.group(1);
final int decimal = Integer.valueOf(match, 16);
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString();
buf = new StringBuffer();
m = P_ENCODE.matcher(s);
while (m.find()) {
final String match = m.group(1);
final int decimal = Integer.valueOf(match, 16);
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString();
s = validateEntities(s);
return s;
}
private String validateEntities(final String s) {
StringBuffer buf = new StringBuffer();
// validate entities throughout the string
Matcher m = P_VALID_ENTITIES.matcher(s);
while (m.find()) {
final String one = m.group(1); // ([^&;]*)
final String two = m.group(2); // (?=(;|&|$))
m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
}
m.appendTail(buf);
return encodeQuotes(buf.toString());
}
private String encodeQuotes(final String s) {
if (encodeQuotes) {
StringBuffer buf = new StringBuffer();
Matcher m = P_VALID_QUOTES.matcher(s);
while (m.find()) {
final String one = m.group(1); // (>|^)
final String two = m.group(2); // ([^<]+?)
final String three = m.group(3); // (<|$)
// 不替换双引号为&quot;防止json格式无效 regexReplace(P_QUOTE, "&quot;", two)
m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three));
}
m.appendTail(buf);
return buf.toString();
} else {
return s;
}
}
private String checkEntity(final String preamble, final String term) {
return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&amp;" + preamble;
}
private boolean isValidEntity(final String entity) {
return inArray(entity, vAllowedEntities);
}
private static boolean inArray(final String s, final String[] array) {
for (String item : array) {
if (item != null && item.equals(s)) {
return true;
}
}
return false;
}
private boolean allowed(final String name) {
return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
}
private boolean allowedAttribute(final String name, final String paramName) {
return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
}
}

View File

@ -1,44 +0,0 @@
package com.cpop.common.utils.http;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/**
* 通用http工具封装
*
* @author DB
*/
public class HttpHelper {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpHelper.class);
public static String getBodyString(ServletRequest request) {
StringBuilder sb = new StringBuilder();
BufferedReader reader = null;
try (InputStream inputStream = request.getInputStream()) {
reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
LOGGER.warn("getBodyString出现问题");
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
LOGGER.error(ExceptionUtils.getMessage(e));
}
}
}
return sb.toString();
}
}

View File

@ -1,376 +0,0 @@
package com.cpop.common.utils.http;
import com.cpop.common.constant.Constants;
import com.cpop.common.utils.StringUtils;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.*;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
/**
* 通用http发送方法
*
* @author DB
*/
public class HttpUtils {
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
/**
* 向指定 URL 发送GET方法的请求
*
* @param url 发送请求的 URL
* @return 所代表远程资源的响应结果
*/
public static String sendGet(String url) {
return sendGet(url, StringUtils.EMPTY);
}
/**
* 向指定 URL 发送GET方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数请求参数应该是 name1=value1&name2=value2 的形式
* @return 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
return sendGet(url, param, Constants.UTF8);
}
/**
* 向指定 URL 发送GET方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数请求参数应该是 name1=value1&name2=value2 的形式
* @param contentType 编码类型
* @return 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param, String contentType) {
StringBuilder result = new StringBuilder();
BufferedReader in = null;
try {
String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
log.info("sendGet - {}", urlNameString);
URL realUrl = new URL(urlNameString);
URLConnection connection = realUrl.openConnection();
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.connect();
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
log.info("recv - {}", result);
} catch (ConnectException e) {
log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
} catch (SocketTimeoutException e) {
log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
} catch (IOException e) {
log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
} catch (Exception e) {
log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
} finally {
try {
if (in != null) {
in.close();
}
} catch (Exception ex) {
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
}
}
return result.toString();
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url) {
BufferedReader in = null;
StringBuilder result = new StringBuilder();
try {
log.info("sendPost - {}", url);
URL realUrl = new URL(url);
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setDoOutput(true);
conn.setDoInput(true);
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
log.info("rev - {}", result);
} catch (ConnectException e) {
log.error("调用HttpUtils.sendPost ConnectException, url=" + url, e);
} catch (SocketTimeoutException e) {
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url, e);
} catch (IOException e) {
log.error("调用HttpUtils.sendPost IOException, url=" + url, e);
} catch (Exception e) {
log.error("调用HttpsUtil.sendPost Exception, url=" + url, e);
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
log.error("调用in.close Exception, url=" + url, ex);
}
}
return result.toString();
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数请求参数应该是 name1=value1&name2=value2 的形式
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
try {
log.info("sendPost - {}", url);
URL realUrl = new URL(url);
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setDoOutput(true);
conn.setDoInput(true);
out = new PrintWriter(conn.getOutputStream());
out.print(param);
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
log.info("recv - {}", result);
} catch (ConnectException e) {
log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
} catch (SocketTimeoutException e) {
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
} catch (IOException e) {
log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
} catch (Exception e) {
log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
}
}
return result.toString();
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数请求参数应该是 name1=value1&name2=value2 的形式
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param, File file) throws IOException {
URL urlObj = new URL(url);
//连接
HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
String result = null;
con.setDoInput(true);
con.setDoOutput(true);
// post方式不能使用缓存
con.setUseCaches(false);
// 设置请求头信息
con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Charset", "UTF-8");
// 设置边界
String BOUNDARY = "----------" + System.currentTimeMillis();
con.setRequestProperty("Content-Type",
"multipart/form-data; boundary="
+ BOUNDARY);
// 请求正文信息
// 第一部分
StringBuilder sb = new StringBuilder();
// 必须多两道线
sb.append("--");
sb.append(BOUNDARY);
sb.append("\r\n");
sb.append("Content-Disposition: form-data;name=\"media\";filelength=\"").append(file.length()).append("\";filename=\"").append(file.getName()).append("\"\r\n");
sb.append("Content-Type:application/octet-stream\r\n\r\n");
byte[] head = sb.toString().getBytes(StandardCharsets.UTF_8);
// 获得输出流
OutputStream out = new DataOutputStream(con.getOutputStream());
// 输出表头
out.write(head);
// 文件正文部分
// 把文件已流文件的方式 推入到url中
DataInputStream in = new DataInputStream(Files.newInputStream(file.toPath()));
int bytes = 0;
byte[] bufferOut = new byte[1024];
while ((bytes = in.read(bufferOut)) != -1) {
out.write(bufferOut, 0, bytes);
}
in.close();
// 结尾部分
// 定义最后数据分隔线
byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes(StandardCharsets.UTF_8);
out.write(foot);
out.flush();
out.close();
StringBuilder buffer = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()))) {
// 定义BufferedReader输入流来读取URL的响应
String line = null;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
result = buffer.toString();
} catch (IOException e) {
System.out.println("发送POST请求出现异常" + e);
e.printStackTrace();
}
return result;
}
public static String sendSSLPost(String url, String param) {
StringBuilder result = new StringBuilder();
String urlNameString = url + "?" + param;
try {
log.info("sendSSLPost - {}", urlNameString);
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
URL console = new URL(urlNameString);
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setSSLSocketFactory(sc.getSocketFactory());
conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
conn.connect();
InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String ret = "";
while ((ret = br.readLine()) != null) {
if (!"".equals(ret.trim())) {
result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
}
}
log.info("recv - {}", result);
conn.disconnect();
br.close();
} catch (ConnectException e) {
log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
} catch (SocketTimeoutException e) {
log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
} catch (IOException e) {
log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
} catch (Exception e) {
log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
}
return result.toString();
}
private static class TrustAnyTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
private static class TrustAnyHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
/**
* 获取请求路径参数
* @param url 请求路径
*/
public static Map<String,Object> getQueryParams(String url) {
try {
Map<String, Object> params = new HashMap<String, Object>();
for (String param : url.split("&")) {
String[] pair = param.split("=");
String key = URLDecoder.decode(pair[0], "UTF-8");
String value = "";
if (pair.length > 1) {
value = URLDecoder.decode(pair[1], "UTF-8");
}
params.put(key, value);
}
return params;
} catch (UnsupportedEncodingException ex) {
throw new AssertionError(ex);
}
}
/**
* okhttpPost请求
* @param url 地址
* @param jsonBody 请求体
*/
public static Response sendOkHttpPost(String url,String jsonBody) throws IOException {
OkHttpClient client = new OkHttpClient().newBuilder().build();
MediaType mediaType = MediaType.Companion.parse("application/json;charset=utf-8");
RequestBody body = RequestBody.Companion.create(jsonBody, mediaType);
Request request = new Request
.Builder()
.url(url)
.post(body)
.addHeader("Content-Type", "application/json")
.build();
return client.newCall(request).execute();
}
/**
* okhttpGet请求
* @param url 地址
*/
public static Response sendOkHttpGet(String url) throws IOException {
OkHttpClient client = new OkHttpClient().newBuilder().build();
Request request = new Request.Builder().url(url).get().build();
return client.newCall(request).execute();
}
}

View File

@ -1,51 +0,0 @@
package com.cpop.common.utils.ip;
import com.alibaba.fastjson.JSONObject;
import com.cpop.common.constant.Constants;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.http.HttpUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
/**
* 获取地址类
*
* @author DB
*/
public class AddressUtils {
private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);
// IP地址查询
public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
@Value("${rockBlade.addressEnabled}")
private static Boolean isAddressEnabled;
// 未知地址
public static final String UN_KNOW = "XX XX";
public static String getRealAddressByIP(String ip) {
String address = UN_KNOW;
// 内网不查询
if (IpUtils.internalIp(ip)) {
return "内网IP";
}
if (isAddressEnabled) {
try {
String rspStr = HttpUtils.sendGet(IP_URL, "ip=" + ip + "&json=true", Constants.GBK);
if (StringUtils.isEmpty(rspStr)) {
log.error("获取地理位置异常 {}", ip);
return UN_KNOW;
}
JSONObject obj = JSONObject.parseObject(rspStr);
String region = obj.getString("pro");
String city = obj.getString("city");
return String.format("%s %s", region, city);
} catch (Exception e) {
log.error("获取地理位置异常 {}", ip);
}
}
return address;
}
}

View File

@ -1,196 +0,0 @@
package com.cpop.common.utils.ip;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.html.EscapeUtil;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 获取IP方法
*
* @author DB
*/
public class IpUtils
{
public static String getIpAddr(HttpServletRequest request)
{
if (request == null)
{
return "unknown";
}
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("X-Forwarded-For");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getRemoteAddr();
}
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : EscapeUtil.clean(ip);
}
public static boolean internalIp(String ip)
{
byte[] addr = textToNumericFormatV4(ip);
return internalIp(addr) || "127.0.0.1".equals(ip);
}
private static boolean internalIp(byte[] addr)
{
if (StringUtils.isNull(addr) || addr.length < 2)
{
return true;
}
final byte b0 = addr[0];
final byte b1 = addr[1];
// 10.x.x.x/8
final byte SECTION_1 = 0x0A;
// 172.16.x.x/12
final byte SECTION_2 = (byte) 0xAC;
final byte SECTION_3 = (byte) 0x10;
final byte SECTION_4 = (byte) 0x1F;
// 192.168.x.x/16
final byte SECTION_5 = (byte) 0xC0;
final byte SECTION_6 = (byte) 0xA8;
switch (b0)
{
case SECTION_1:
return true;
case SECTION_2:
if (b1 >= SECTION_3 && b1 <= SECTION_4)
{
return true;
}
case SECTION_5:
switch (b1)
{
case SECTION_6:
return true;
}
default:
return false;
}
}
/**
* 将IPv4地址转换成字节
*
* @param text IPv4地址
* @return byte 字节
*/
public static byte[] textToNumericFormatV4(String text)
{
if (text.length() == 0)
{
return null;
}
byte[] bytes = new byte[4];
String[] elements = text.split("\\.", -1);
try
{
long l;
int i;
switch (elements.length)
{
case 1:
l = Long.parseLong(elements[0]);
if ((l < 0L) || (l > 4294967295L)) {
return null;
}
bytes[0] = (byte) (int) (l >> 24 & 0xFF);
bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 2:
l = Integer.parseInt(elements[0]);
if ((l < 0L) || (l > 255L)) {
return null;
}
bytes[0] = (byte) (int) (l & 0xFF);
l = Integer.parseInt(elements[1]);
if ((l < 0L) || (l > 16777215L)) {
return null;
}
bytes[1] = (byte) (int) (l >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 3:
for (i = 0; i < 2; ++i)
{
l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L)) {
return null;
}
bytes[i] = (byte) (int) (l & 0xFF);
}
l = Integer.parseInt(elements[2]);
if ((l < 0L) || (l > 65535L)) {
return null;
}
bytes[2] = (byte) (int) (l >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 4:
for (i = 0; i < 4; ++i)
{
l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L)) {
return null;
}
bytes[i] = (byte) (int) (l & 0xFF);
}
break;
default:
return null;
}
}
catch (NumberFormatException e)
{
return null;
}
return bytes;
}
public static String getHostIp()
{
try
{
return InetAddress.getLocalHost().getHostAddress();
}
catch (UnknownHostException e)
{
}
return "127.0.0.1";
}
public static String getHostName()
{
try
{
return InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException e)
{
}
return "未知";
}
}

View File

@ -1,91 +0,0 @@
package com.cpop.common.utils.text;
import com.cpop.common.utils.StringUtils;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* 字符集工具类
*
* @author DB
*/
public class CharsetKit {
/**
* ISO-8859-1
*/
public static final String ISO_8859_1 = "ISO-8859-1";
/**
* UTF-8
*/
public static final String UTF_8 = "UTF-8";
/**
* GBK
*/
public static final String GBK = "GBK";
/**
* ISO-8859-1
*/
public static final Charset CHARSET_ISO_8859_1 = StandardCharsets.ISO_8859_1;
/**
* UTF-8
*/
public static final Charset CHARSET_UTF_8 = StandardCharsets.UTF_8;
/**
* GBK
*/
public static final Charset CHARSET_GBK = Charset.forName(GBK);
/**
* 转换为Charset对象
*
* @param charset 字符集为空则返回默认字符集
* @return Charset
*/
public static Charset charset(String charset) {
return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
}
/**
* 转换字符串的字符集编码
*
* @param source 字符串
* @param srcCharset 源字符集默认ISO-8859-1
* @param destCharset 目标字符集默认UTF-8
* @return 转换后的字符集
*/
public static String convert(String source, String srcCharset, String destCharset) {
return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));
}
/**
* 转换字符串的字符集编码
*
* @param source 字符串
* @param srcCharset 源字符集默认ISO-8859-1
* @param destCharset 目标字符集默认UTF-8
* @return 转换后的字符集
*/
public static String convert(String source, Charset srcCharset, Charset destCharset) {
if (null == srcCharset) {
srcCharset = StandardCharsets.ISO_8859_1;
}
if (null == destCharset) {
destCharset = StandardCharsets.UTF_8;
}
if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) {
return source;
}
return new String(source.getBytes(srcCharset), destCharset);
}
/**
* @return 系统字符集编码
*/
public static String systemCharset() {
return Charset.defaultCharset().name();
}
}

View File

@ -1,854 +0,0 @@
package com.cpop.common.utils.text;
import com.cpop.common.utils.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.util.Set;
/**
* 类型转换器
*
* @author DB
*/
public class Convert {
/**
* 转换为字符串<br>
* 如果给定的值为null或者转换失败返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static String toStr(Object value, String defaultValue) {
if (null == value) {
return defaultValue;
}
if (value instanceof String) {
return (String) value;
}
return value.toString();
}
/**
* 转换为字符串<br>
* 如果给定的值为<code>null</code>或者转换失败返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static String toStr(Object value) {
return toStr(value, null);
}
/**
* 转换为字符<br>
* 如果给定的值为null或者转换失败返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Character toChar(Object value, Character defaultValue) {
if (null == value) {
return defaultValue;
}
if (value instanceof Character) {
return (Character) value;
}
final String valueStr = toStr(value, null);
return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
}
/**
* 转换为字符<br>
* 如果给定的值为<code>null</code>或者转换失败返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Character toChar(Object value) {
return toChar(value, null);
}
/**
* 转换为byte<br>
* 如果给定的值为<code>null</code>或者转换失败返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Byte toByte(Object value, Byte defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Byte) {
return (Byte) value;
}
if (value instanceof Number) {
return ((Number) value).byteValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Byte.parseByte(valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为byte<br>
* 如果给定的值为<code>null</code>或者转换失败返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Byte toByte(Object value) {
return toByte(value, null);
}
/**
* 转换为Short<br>
* 如果给定的值为<code>null</code>或者转换失败返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Short toShort(Object value, Short defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Short) {
return (Short) value;
}
if (value instanceof Number) {
return ((Number) value).shortValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Short.parseShort(valueStr.trim());
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为Short<br>
* 如果给定的值为<code>null</code>或者转换失败返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Short toShort(Object value) {
return toShort(value, null);
}
/**
* 转换为Number<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Number toNumber(Object value, Number defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Number) {
return (Number) value;
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return NumberFormat.getInstance().parse(valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为Number<br>
* 如果给定的值为空或者转换失败返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Number toNumber(Object value) {
return toNumber(value, null);
}
/**
* 转换为int<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Integer toInt(Object value, Integer defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Integer) {
return (Integer) value;
}
if (value instanceof Number) {
return ((Number) value).intValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Integer.parseInt(valueStr.trim());
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为int<br>
* 如果给定的值为<code>null</code>或者转换失败返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Integer toInt(Object value) {
return toInt(value, null);
}
/**
* 转换为Integer数组<br>
*
* @param str 被转换的值
* @return 结果
*/
public static Integer[] toIntArray(String str) {
return toIntArray(",", str);
}
/**
* 转换为Long数组<br>
*
* @param str 被转换的值
* @return 结果
*/
public static Long[] toLongArray(String str) {
return toLongArray(",", str);
}
/**
* 转换为Integer数组<br>
*
* @param split 分隔符
* @param split 被转换的值
* @return 结果
*/
public static Integer[] toIntArray(String split, String str) {
if (StringUtils.isEmpty(str)) {
return new Integer[]{};
}
String[] arr = str.split(split);
final Integer[] ints = new Integer[arr.length];
for (int i = 0; i < arr.length; i++) {
final Integer v = toInt(arr[i], 0);
ints[i] = v;
}
return ints;
}
/**
* 转换为Long数组<br>
*
* @param split 分隔符
* @param str 被转换的值
* @return 结果
*/
public static Long[] toLongArray(String split, String str) {
if (StringUtils.isEmpty(str)) {
return new Long[]{};
}
String[] arr = str.split(split);
final Long[] longs = new Long[arr.length];
for (int i = 0; i < arr.length; i++) {
final Long v = toLong(arr[i], null);
longs[i] = v;
}
return longs;
}
/**
* 转换为String数组<br>
*
* @param str 被转换的值
* @return 结果
*/
public static String[] toStrArray(String str) {
return toStrArray(",", str);
}
/**
* 转换为String数组<br>
*
* @param split 分隔符
* @param split 被转换的值
* @return 结果
*/
public static String[] toStrArray(String split, String str) {
return str.split(split);
}
/**
* 转换为long<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Long toLong(Object value, Long defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Long) {
return (Long) value;
}
if (value instanceof Number) {
return ((Number) value).longValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
// 支持科学计数法
return new BigDecimal(valueStr.trim()).longValue();
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为long<br>
* 如果给定的值为<code>null</code>或者转换失败返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Long toLong(Object value) {
return toLong(value, null);
}
/**
* 转换为double<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Double toDouble(Object value, Double defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Double) {
return (Double) value;
}
if (value instanceof Number) {
return ((Number) value).doubleValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
// 支持科学计数法
return new BigDecimal(valueStr.trim()).doubleValue();
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为double<br>
* 如果给定的值为空或者转换失败返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Double toDouble(Object value) {
return toDouble(value, null);
}
/**
* 转换为Float<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Float toFloat(Object value, Float defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Float) {
return (Float) value;
}
if (value instanceof Number) {
return ((Number) value).floatValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Float.parseFloat(valueStr.trim());
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为Float<br>
* 如果给定的值为空或者转换失败返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Float toFloat(Object value) {
return toFloat(value, null);
}
/**
* 转换为boolean<br>
* String支持的值为truefalseyesokno1,0 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Boolean toBool(Object value, Boolean defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Boolean) {
return (Boolean) value;
}
String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
valueStr = valueStr.trim().toLowerCase();
switch (valueStr) {
case "true":
return true;
case "false":
return false;
case "yes":
return true;
case "ok":
return true;
case "no":
return false;
case "1":
return true;
case "0":
return false;
default:
return defaultValue;
}
}
/**
* 转换为boolean<br>
* 如果给定的值为空或者转换失败返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Boolean toBool(Object value) {
return toBool(value, null);
}
/**
* 转换为Enum对象<br>
* 如果给定的值为空或者转换失败返回默认值<br>
*
* @param clazz Enum的Class
* @param value
* @param defaultValue 默认值
* @return Enum
*/
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) {
if (value == null) {
return defaultValue;
}
if (clazz.isAssignableFrom(value.getClass())) {
@SuppressWarnings("unchecked")
E myE = (E) value;
return myE;
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Enum.valueOf(clazz, valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为Enum对象<br>
* 如果给定的值为空或者转换失败返回默认值<code>null</code><br>
*
* @param clazz Enum的Class
* @param value
* @return Enum
*/
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value) {
return toEnum(clazz, value, null);
}
/**
* 转换为BigInteger<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static BigInteger toBigInteger(Object value, BigInteger defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof BigInteger) {
return (BigInteger) value;
}
if (value instanceof Long) {
return BigInteger.valueOf((Long) value);
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return new BigInteger(valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为BigInteger<br>
* 如果给定的值为空或者转换失败返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static BigInteger toBigInteger(Object value) {
return toBigInteger(value, null);
}
/**
* 转换为BigDecimal<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof BigDecimal) {
return (BigDecimal) value;
}
if (value instanceof Long) {
return new BigDecimal((Long) value);
}
if (value instanceof Double) {
return new BigDecimal((Double) value);
}
if (value instanceof Integer) {
return new BigDecimal((Integer) value);
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return new BigDecimal(valueStr);
} catch (Exception e) {
return defaultValue;
}
}
/**
* 转换为BigDecimal<br>
* 如果给定的值为空或者转换失败返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static BigDecimal toBigDecimal(Object value) {
return toBigDecimal(value, null);
}
/**
* 将对象转为字符串<br>
* 1Byte数组和ByteBuffer会被转换为对应字符串的数组 2对象数组会调用Arrays.toString方法
*
* @param obj 对象
* @return 字符串
*/
public static String utf8Str(Object obj) {
return str(obj, CharsetKit.CHARSET_UTF_8);
}
/**
* 将对象转为字符串<br>
* 1Byte数组和ByteBuffer会被转换为对应字符串的数组 2对象数组会调用Arrays.toString方法
*
* @param obj 对象
* @param charsetName 字符集
* @return 字符串
*/
public static String str(Object obj, String charsetName) {
return str(obj, Charset.forName(charsetName));
}
/**
* 将对象转为字符串<br>
* 1Byte数组和ByteBuffer会被转换为对应字符串的数组 2对象数组会调用Arrays.toString方法
*
* @param obj 对象
* @param charset 字符集
* @return 字符串
*/
public static String str(Object obj, Charset charset) {
if (null == obj) {
return null;
}
if (obj instanceof String) {
return (String) obj;
} else if (obj instanceof byte[]) {
return str((byte[]) obj, charset);
} else if (obj instanceof Byte[]) {
byte[] bytes = ArrayUtils.toPrimitive((Byte[]) obj);
return str(bytes, charset);
} else if (obj instanceof ByteBuffer) {
return str((ByteBuffer) obj, charset);
}
return obj.toString();
}
/**
* 将byte数组转为字符串
*
* @param bytes byte数组
* @param charset 字符集
* @return 字符串
*/
public static String str(byte[] bytes, String charset) {
return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
}
/**
* 解码字节码
*
* @param data 字符串
* @param charset 字符集如果此字段为空则解码的结果取决于平台
* @return 解码后的字符串
*/
public static String str(byte[] data, Charset charset) {
if (data == null) {
return null;
}
if (null == charset) {
return new String(data);
}
return new String(data, charset);
}
/**
* 将编码的byteBuffer数据转换为字符串
*
* @param data 数据
* @param charset 字符集如果为空使用当前系统字符集
* @return 字符串
*/
public static String str(ByteBuffer data, String charset) {
if (data == null) {
return null;
}
return str(data, Charset.forName(charset));
}
/**
* 将编码的byteBuffer数据转换为字符串
*
* @param data 数据
* @param charset 字符集如果为空使用当前系统字符集
* @return 字符串
*/
public static String str(ByteBuffer data, Charset charset) {
if (null == charset) {
charset = Charset.defaultCharset();
}
return charset.decode(data).toString();
}
// ----------------------------------------------------------------------- 全角半角转换
/**
* 半角转全角
*
* @param input String.
* @return 全角字符串.
*/
public static String toSBC(String input) {
return toSBC(input, null);
}
/**
* 半角转全角
*
* @param input String
* @param notConvertSet 不替换的字符集合
* @return 全角字符串.
*/
public static String toSBC(String input, Set<Character> notConvertSet) {
char c[] = input.toCharArray();
for (int i = 0; i < c.length; i++) {
if (null != notConvertSet && notConvertSet.contains(c[i])) {
// 跳过不替换的字符
continue;
}
if (c[i] == ' ') {
c[i] = '\u3000';
} else if (c[i] < '\177') {
c[i] = (char) (c[i] + 65248);
}
}
return new String(c);
}
/**
* 全角转半角
*
* @param input String.
* @return 半角字符串
*/
public static String toDBC(String input) {
return toDBC(input, null);
}
/**
* 替换全角为半角
*
* @param text 文本
* @param notConvertSet 不替换的字符集合
* @return 替换后的字符
*/
public static String toDBC(String text, Set<Character> notConvertSet) {
char c[] = text.toCharArray();
for (int i = 0; i < c.length; i++) {
if (null != notConvertSet && notConvertSet.contains(c[i])) {
// 跳过不替换的字符
continue;
}
if (c[i] == '\u3000') {
c[i] = ' ';
} else if (c[i] > '\uFF00' && c[i] < '\uFF5F') {
c[i] = (char) (c[i] - 65248);
}
}
String returnString = new String(c);
return returnString;
}
/**
* 数字金额大写转换 先写个完整的然后将如零拾替换成零
*
* @param n 数字
* @return 中文大写数字
*/
public static String digitUppercase(double n) {
String[] fraction = {"", ""};
String[] digit = {"", "", "", "", "", "", "", "", "", ""};
String[][] unit = {{"", "", "亿"}, {"", "", "", ""}};
String head = n < 0 ? "" : "";
n = Math.abs(n);
String s = "";
for (int i = 0; i < fraction.length; i++) {
s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
}
if (s.length() < 1) {
s = "";
}
int integerPart = (int) Math.floor(n);
for (int i = 0; i < unit[0].length && integerPart > 0; i++) {
String p = "";
for (int j = 0; j < unit[1].length && n > 0; j++) {
p = digit[integerPart % 10] + unit[1][j] + p;
integerPart = integerPart / 10;
}
s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "") + unit[0][i] + s;
}
return head + s.replaceAll("(零.)*零元", "").replaceFirst("(零.)+", "").replaceAll("(零.)+", "").replaceAll("^整$", "零元整");
}
}

View File

@ -1,77 +0,0 @@
package com.cpop.common.utils.text;
import com.cpop.common.utils.StringUtils;
/**
* 字符串格式化
*
* @author DB
*/
public class StrFormatter {
public static final String EMPTY_JSON = "{}";
public static final char C_BACKSLASH = '\\';
public static final char C_DELIM_START = '{';
public static final char C_DELIM_END = '}';
/**
* 格式化字符串<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* <br>
* 通常使用format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{} format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\ format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param strPattern 字符串模板
* @param argArray 参数列表
* @return 结果
*/
public static String format(final String strPattern, final Object... argArray) {
if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray)) {
return strPattern;
}
final int strPatternLength = strPattern.length();
// 初始化定义好的长度以获得更好的性能
StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
int handledPosition = 0;
int delimIndex;// 占位符所在位置
for (int argIndex = 0; argIndex < argArray.length; argIndex++) {
delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);
if (delimIndex == -1) {
if (handledPosition == 0) {
return strPattern;
} else { // 字符串模板剩余部分不再包含占位符加入剩余部分后返回结果
sbuf.append(strPattern, handledPosition, strPatternLength);
return sbuf.toString();
}
} else {
if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) {
if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) {
// 转义符之前还有一个转义符占位符依旧有效
sbuf.append(strPattern, handledPosition, delimIndex - 1);
sbuf.append(Convert.utf8Str(argArray[argIndex]));
handledPosition = delimIndex + 2;
} else {
// 占位符被转义
argIndex--;
sbuf.append(strPattern, handledPosition, delimIndex - 1);
sbuf.append(C_DELIM_START);
handledPosition = delimIndex + 1;
}
} else {
// 正常占位符
sbuf.append(strPattern, handledPosition, delimIndex);
sbuf.append(Convert.utf8Str(argArray[argIndex]));
handledPosition = delimIndex + 2;
}
}
}
// 加入最后一个占位符后所有的字符
sbuf.append(strPattern, handledPosition, strPattern.length());
return sbuf.toString();
}
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>com.cpop</groupId>
<artifactId>Cpop-Union</artifactId>
<version>1.0.0</version>
<version>1.1.2</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>Cpop-Core</artifactId>
@ -14,45 +14,20 @@
<packaging>jar</packaging>
<dependencies>
<!--Cpop公共包-->
<!-- Sa-Token 权限认证在线文档https://sa-token.cc -->
<dependency>
<groupId>com.cpop</groupId>
<artifactId>Cpop-Common</artifactId>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
</dependency>
<!--AOP-->
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
</dependency>
<!--Mybatis-flex-->
<!-- 提供Redis连接池 -->
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-processor</artifactId>
</dependency>
<!--Security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- jwt 相关依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<!--Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
@ -67,55 +42,76 @@
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-redis</artifactId>
</dependency>
<!--easyExcel-->
<!-- Sa-Token 整合 jwt -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-compress -->
<!--Mysql-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!--HikariCP-->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<!--knife4j-Swagger-->
<!--Mybatis-flex-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-spring-boot3-starter</artifactId>
</dependency>
<!-- 自定义验证注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-processor</artifactId>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<!--easyExcel-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<!--quartz-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!-- 腾讯云-->
<!-- Sa-Token 整合 SpringAOP 实现注解鉴权 -->
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-aop</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<!-- 自定义验证注解 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--knife4j-Swagger-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<!--mongo-plus-->
<dependency>
<groupId>com.gitee.anwena</groupId>
<artifactId>mongo-plus-boot-starter</artifactId>
</dependency>
<!--hutool工具-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<!--谷歌拓展集合类-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -1,4 +1,4 @@
package com.cpop.core.annontation;
package com.cpop.core.anno;
import com.cpop.core.base.enums.OperationLogEnum;

View File

@ -1,4 +1,4 @@
package com.cpop.core.annontation;
package com.cpop.core.anno;
import java.lang.annotation.*;

View File

@ -1,4 +1,4 @@
package com.cpop.core.annontation;
package com.cpop.core.anno;
import java.lang.annotation.*;

View File

@ -1,4 +1,4 @@
package com.cpop.core.annontation;
package com.cpop.core.anno;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

View File

@ -1,15 +1,16 @@
package com.cpop.core.aspect;
import com.cpop.common.constant.HttpStatus;
import com.cpop.common.enums.ErrorCodeEnum;
import com.cpop.core.base.R;
import com.cpop.core.base.entity.LoginUser;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import com.cpop.core.base.entity.R;
import com.cpop.core.base.enums.ErrorCodeEnum;
import com.cpop.core.base.enums.OperationLogEnum;
import com.cpop.core.base.enums.UserType;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.table.SysOperationLog;
import com.cpop.core.base.table.OperationLog;
import com.cpop.core.constant.HttpStatus;
import com.cpop.core.event.OperationLogEvent;
import com.cpop.core.utils.MessageUtils;
import com.cpop.core.utils.SecurityUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
@ -29,7 +30,7 @@ import org.springframework.stereotype.Component;
@Component
public class OperationLogAspect {
private final SysOperationLog operationLog = new SysOperationLog();
private final OperationLog operationLog = new OperationLog();
private OperationLogEnum operationLogEnum;
@ -42,7 +43,7 @@ public class OperationLogAspect {
/**
* 定义controller切入点拦截规则拦截SysLog注解的方法
*/
@Pointcut("@annotation(com.cpop.core.annontation.OperationLog)")
@Pointcut("@annotation(com.cpop.core.anno.OperationLog)")
public void operationLogAspect() {
}
@ -57,18 +58,16 @@ public class OperationLogAspect {
public void recordLog(JoinPoint joinPoint) {
//设置枚举信息
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
com.cpop.core.annontation.OperationLog annotation = signature.getMethod().getAnnotation(com.cpop.core.annontation.OperationLog.class);
com.cpop.core.anno.OperationLog annotation = signature.getMethod().getAnnotation(com.cpop.core.anno.OperationLog.class);
operationLogEnum = annotation.operationLogEnumType();
try {
LoginUser loginUser = SecurityUtils.getInstance().getLoginUser();
operationLog.setOperationUserName(loginUser.getUsername())
.setOperationUserId(loginUser.getUserId())
.setOperationUserType(loginUser.getUserType())
.setDevIp(loginUser.getIpAddr())
SaSession session = StpUtil.getSession();
operationLog.setOperationUserName(session.getString("username"))
.setOperationUserId(session.getString("userId"))
.setOperationUserType((UserType) session.get("userType"))
.setDevIp(session.getString("loginIp"))
.setCode(operationLogEnum.getCode())
.setInfo(MessageUtils.message(operationLogEnum.getInfo()))
.setCreateUserId(loginUser.getUserId());
operationLog.setUpdateUserId(loginUser.getUserId());
.setInfo(MessageUtils.message(operationLogEnum.getInfo()));
} catch (Exception e) {
throw new ServiceException(ErrorCodeEnum.OPERATION_LOG_EXCEPTION.getInfo(), ErrorCodeEnum.OPERATION_LOG_EXCEPTION.getCode());
}

View File

@ -1,10 +1,10 @@
package com.cpop.core.aspect;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.R;
import cn.hutool.core.util.StrUtil;
import com.cpop.core.base.entity.R;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.exception.UtilException;
import com.cpop.core.utils.RsaUtils;
import com.cpop.core.config.CpopConfig;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
@ -15,16 +15,7 @@ import org.springframework.util.DigestUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Key;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -43,14 +34,14 @@ import java.util.stream.Collectors;
public class SignatureCheckAspect {
@Autowired
private RsaUtils rsaUtils;
private CpopConfig cpopConfig;
private static final Map<String, String[]> APP_IDS = new HashMap<String, String[]>() {{
//数币
put("1688842965582499840", new String[]{"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmsFHkB4iIdVSgaz8u8QG66wiZupgSbu2T/ml/kdPm2vemsKgvEqUqp1gR6ulfHcPF8otjVbjiE8q8oR70XfxFIREbomTUmpsOzurLFrAmVhyvu6/tY23/txjQoeeH/tlCy7Lq/TL1AqPKyBcGzsQ4yInpIgRWpXz7fmJCTRw07tyE+4lpXBqiaLdWrkkGG00LnHQAOfcUoXf0TdxFPSfRHiBikfbkmgeVoU66RGlUEXU2esTY2nYGvFn+FqWsNkGEnn2YxIqgbQQ1zNX33+FWBlba1WdQtc8mTJAleaPGXmFnQiEMb55b7xVPjyyCWt6aRwl97KQgtCmfsoPZUWwQQIDAQAB", "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCawUeQHiIh1VKBrPy7xAbrrCJm6mBJu7ZP+aX+R0+ba96awqC8SpSqnWBHq6V8dw8Xyi2NVuOITyryhHvRd/EUhERuiZNSamw7O6ssWsCZWHK+7r+1jbf+3GNCh54f+2ULLsur9MvUCo8rIFwbOxDjIiekiBFalfPt+YkJNHDTu3IT7iWlcGqJot1auSQYbTQucdAA59xShd/RN3EU9J9EeIGKR9uSaB5WhTrpEaVQRdTZ6xNjadga8Wf4Wpaw2QYSefZjEiqBtBDXM1fff4VYGVtrVZ1C1zyZMkCV5o8ZeYWdCIQxvnlvvFU+PLIJa3ppHCX3spCC0KZ+yg9lRbBBAgMBAAECggEAdstPp+25vccHYsvr5icAOQEWF3JrH66csJ+vMJaFIYWYh6xHvsJxhNbyBZJZokWyrExi01CTsRs0mJ3iflVYFqvB7ChnkqhnFMElERNJLW2cB702JKP5TgbXm0aHt30/f2oYppNvtAG3DR/2FGEvAWxCiiZ5S9Q4P8GB1DMROTZBpYQgVlN9vOxqgcy8SsJyruy0xsEP3RIKko9UQ7Y9y/b6TbNOJDx/ZpC9KcOUmI8Or73IMdG1ZucumzHNO3dS2XKL7qeTQ8AWMwwAk2ZsCRx9g05QLiW3+7ZrpmOMwI3wCeJOoxhUQKijCXI3B8Rh1cU++CMk4LdyPOe78PYEEQKBgQDnyOL69Ck6+xe1EJ2HAEDPla5ujCexv6ctYvSernhI6OsMVCWa1D5rCqzC4L0IvRW7/m5lUSWlSzpfIGhSGc+PNyIaYsyYMbaIV5e8LKRp8SxUDrTA4IfYmxoXdYyq2l0PSkBPKMJ2ZyWlRoGGEC432IsiY+GBaznvHwIYFvkYHwKBgQCq7DkJYT6du/bQ2uoZv6hYYIGTY4A9TzjJ0Kp5O00BUz5zNpgBUfb1SmuISHwGyN1hOWFntR0uwfj/BUDvtG0b07k1Xz+4UWXsDqtS6eEnvUR6q/i2yWWGjCMS74t61FZopV6AxHneJV2S6Tt26MFK0VbrCwXaiYg/3tMYgC2rnwKBgF0kfRIby/XHsV8xrhvyHhlNLSt/ZvQm8Cds/KBHvE6QSuRJbFMrt2mMgKBPb6dzVKiXNgXA9j/WWz6e500W0jHbFflEerMuRwvDJ1aXGfr4z7d3sWtQz0ZcDcAfnMeLuJnMXMtytbKfAKHKE4KsPeZzPnYzbQt063MMIutLUA5BAoGBAIduFONxwgOJY8+pJcSxL9qW3RTDymDJ3N1MEUdtzV43b0wq/dZN87f396xMgrl9fqwCo0NhJnZeC8VFjGZiN/HMmPvJNNv+4xtfpDBWUKkENrZcfP2YJnGtqDzgwUvZ432XSoINK+LxCGvXkd5uHnoB1TT3zvOR9ftluy22onlRAoGBAKkIZmwW/2H/86ILrCDyARK4obULB4op8IyrunZ+lH14DksxbL7fmTsSbLyRX7oD/QvGJIuc0EDkgONztsAn5vrETv8Z6RqyKdoZZI3sAQWIBc0om6nH2zqJDIs+mep96DOg/jJAcgiVhyIoFP91IvHY7pvKwy5MTttdZLvvS2XB"});
}};
@Pointcut("@annotation(com.cpop.core.annontation.SignatureCheck)")
@Pointcut("@annotation(com.cpop.core.anno.SignatureCheck)")
public void signatureCheck() {}
/**
@ -76,11 +67,11 @@ public class SignatureCheckAspect {
String appId = null;
for (Field field : fatherFields) {
field.setAccessible(true);
if (StringUtils.equals("signature", field.getName())) {
if (StrUtil.equals("signature", field.getName())) {
signature = (String) field.get(object);
continue;
}
if (StringUtils.equals("appId", field.getName())) {
if (StrUtil.equals("appId", field.getName())) {
String[] strings = APP_IDS.get((String) field.get(object));
if (null == strings){
throw new ServiceException("appId匹配失败,请核实appId");
@ -108,7 +99,7 @@ public class SignatureCheckAspect {
//按照字母排序
String sign = signString.stream().sorted().collect(Collectors.joining("&")) + appId;
String md5DigestAsHex = DigestUtils.md5DigestAsHex(sign.getBytes());
if (!StringUtils.equals(md5DigestAsHex,signature)){
if (!StrUtil.equals(md5DigestAsHex,signature)){
throw new ServiceException("签名匹配失败,请核实签名");
}
}

View File

@ -1,10 +1,13 @@
package com.cpop.core.aspect;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.R;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.cpop.core.base.entity.R;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.exception.UtilException;
import com.cpop.core.utils.RsaUtils;
import com.cpop.core.config.CpopConfig;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
@ -15,19 +18,11 @@ import org.springframework.util.DigestUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.crypto.Cipher;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
@ -43,7 +38,7 @@ import java.util.Map;
public class SimpleSignatureCheckAspect {
@Autowired
private RsaUtils rsaUtils;
private CpopConfig cpopConfig;
private static final Map<String, String[]> APP_IDS = new HashMap<String, String[]>() {{
//果酱内部
@ -53,7 +48,7 @@ public class SimpleSignatureCheckAspect {
put("1688842965582499840", new String[]{"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmsFHkB4iIdVSgaz8u8QG66wiZupgSbu2T/ml/kdPm2vemsKgvEqUqp1gR6ulfHcPF8otjVbjiE8q8oR70XfxFIREbomTUmpsOzurLFrAmVhyvu6/tY23/txjQoeeH/tlCy7Lq/TL1AqPKyBcGzsQ4yInpIgRWpXz7fmJCTRw07tyE+4lpXBqiaLdWrkkGG00LnHQAOfcUoXf0TdxFPSfRHiBikfbkmgeVoU66RGlUEXU2esTY2nYGvFn+FqWsNkGEnn2YxIqgbQQ1zNX33+FWBlba1WdQtc8mTJAleaPGXmFnQiEMb55b7xVPjyyCWt6aRwl97KQgtCmfsoPZUWwQQIDAQAB", "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCawUeQHiIh1VKBrPy7xAbrrCJm6mBJu7ZP+aX+R0+ba96awqC8SpSqnWBHq6V8dw8Xyi2NVuOITyryhHvRd/EUhERuiZNSamw7O6ssWsCZWHK+7r+1jbf+3GNCh54f+2ULLsur9MvUCo8rIFwbOxDjIiekiBFalfPt+YkJNHDTu3IT7iWlcGqJot1auSQYbTQucdAA59xShd/RN3EU9J9EeIGKR9uSaB5WhTrpEaVQRdTZ6xNjadga8Wf4Wpaw2QYSefZjEiqBtBDXM1fff4VYGVtrVZ1C1zyZMkCV5o8ZeYWdCIQxvnlvvFU+PLIJa3ppHCX3spCC0KZ+yg9lRbBBAgMBAAECggEAdstPp+25vccHYsvr5icAOQEWF3JrH66csJ+vMJaFIYWYh6xHvsJxhNbyBZJZokWyrExi01CTsRs0mJ3iflVYFqvB7ChnkqhnFMElERNJLW2cB702JKP5TgbXm0aHt30/f2oYppNvtAG3DR/2FGEvAWxCiiZ5S9Q4P8GB1DMROTZBpYQgVlN9vOxqgcy8SsJyruy0xsEP3RIKko9UQ7Y9y/b6TbNOJDx/ZpC9KcOUmI8Or73IMdG1ZucumzHNO3dS2XKL7qeTQ8AWMwwAk2ZsCRx9g05QLiW3+7ZrpmOMwI3wCeJOoxhUQKijCXI3B8Rh1cU++CMk4LdyPOe78PYEEQKBgQDnyOL69Ck6+xe1EJ2HAEDPla5ujCexv6ctYvSernhI6OsMVCWa1D5rCqzC4L0IvRW7/m5lUSWlSzpfIGhSGc+PNyIaYsyYMbaIV5e8LKRp8SxUDrTA4IfYmxoXdYyq2l0PSkBPKMJ2ZyWlRoGGEC432IsiY+GBaznvHwIYFvkYHwKBgQCq7DkJYT6du/bQ2uoZv6hYYIGTY4A9TzjJ0Kp5O00BUz5zNpgBUfb1SmuISHwGyN1hOWFntR0uwfj/BUDvtG0b07k1Xz+4UWXsDqtS6eEnvUR6q/i2yWWGjCMS74t61FZopV6AxHneJV2S6Tt26MFK0VbrCwXaiYg/3tMYgC2rnwKBgF0kfRIby/XHsV8xrhvyHhlNLSt/ZvQm8Cds/KBHvE6QSuRJbFMrt2mMgKBPb6dzVKiXNgXA9j/WWz6e500W0jHbFflEerMuRwvDJ1aXGfr4z7d3sWtQz0ZcDcAfnMeLuJnMXMtytbKfAKHKE4KsPeZzPnYzbQt063MMIutLUA5BAoGBAIduFONxwgOJY8+pJcSxL9qW3RTDymDJ3N1MEUdtzV43b0wq/dZN87f396xMgrl9fqwCo0NhJnZeC8VFjGZiN/HMmPvJNNv+4xtfpDBWUKkENrZcfP2YJnGtqDzgwUvZ432XSoINK+LxCGvXkd5uHnoB1TT3zvOR9ftluy22onlRAoGBAKkIZmwW/2H/86ILrCDyARK4obULB4op8IyrunZ+lH14DksxbL7fmTsSbLyRX7oD/QvGJIuc0EDkgONztsAn5vrETv8Z6RqyKdoZZI3sAQWIBc0om6nH2zqJDIs+mep96DOg/jJAcgiVhyIoFP91IvHY7pvKwy5MTttdZLvvS2XB"});
}};
@Pointcut("@annotation(com.cpop.core.annontation.SimpleSignatureCheck)")
@Pointcut("@annotation(com.cpop.core.anno.SimpleSignatureCheck)")
public void simpleSignatureCheck() {}
/**
@ -70,21 +65,22 @@ public class SimpleSignatureCheckAspect {
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
assert request != null;
String signature = request.getHeader("signature");
if (StringUtils.isBlank(signature)){
if (StrUtil.isBlank(signature)){
throw new ServiceException("签名为空,请核实签名");
}
String appId = request.getHeader("appId");
if (StringUtils.isBlank(appId)){
if (StrUtil.isBlank(appId)){
throw new ServiceException("appId为空,请核实签名");
}
String dateTime = request.getHeader("dateTime");
if (StringUtils.isBlank(dateTime)){
if (StrUtil.isBlank(dateTime)){
throw new ServiceException("时间为空,请核实签名");
}
String decrypt = rsaUtils.decrypt(signature, stringToKey(APP_IDS.get(appId)[1]));
RSA rsa = SecureUtil.rsa(APP_IDS.get(appId)[1], null);
String decrypt = rsa.decryptStr(signature, KeyType.PrivateKey);
String sign = appId + dateTime;
String md5DigestAsHex = DigestUtils.md5DigestAsHex(sign.getBytes());
if (!StringUtils.equals(md5DigestAsHex, decrypt)) {
if (!StrUtil.equals(md5DigestAsHex, decrypt)) {
throw new ServiceException("签名匹配失败,请核实签名");
}
}

View File

@ -1,6 +1,8 @@
package com.cpop.core.base.entity;
import com.cpop.core.utils.SecurityUtils;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.stp.StpUtil;
import com.cpop.core.constant.Constants;
import com.mybatisflex.annotation.InsertListener;
import java.time.LocalDateTime;
@ -15,11 +17,16 @@ public class BaseInsertListener implements InsertListener {
@Override
public void onInsert(Object entity) {
BaseEntity baseEntity = (BaseEntity) entity;
LoginUser loginUser = SecurityUtils.getInstance().getLoginUser();
//设置 account 被新增时的一些默认数据
String userId;
try {
userId = StpUtil.getLoginIdDefaultNull() == null ? Constants.SUPER_ADMIN_ID : StpUtil.getLoginIdDefaultNull().toString();
} catch (SaTokenException e) {
userId = Constants.SUPER_ADMIN_ID;
}
baseEntity.setCreateTime(LocalDateTime.now());
baseEntity.setCreateUserId(null == loginUser ? "1" : loginUser.getUserId());
baseEntity.setCreateUserId(userId);
baseEntity.setUpdateTime(LocalDateTime.now());
baseEntity.setUpdateUserId(null == loginUser ? "1" : loginUser.getUserId());
baseEntity.setUpdateUserId(userId);
}
}

View File

@ -1,6 +1,8 @@
package com.cpop.core.base.entity;
import com.cpop.core.utils.SecurityUtils;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.stp.StpUtil;
import com.cpop.core.constant.Constants;
import com.mybatisflex.annotation.UpdateListener;
import java.time.LocalDateTime;
@ -15,9 +17,14 @@ public class BaseUpdateListener implements UpdateListener {
@Override
public void onUpdate(Object entity) {
BaseEntity baseEntity = (BaseEntity) entity;
LoginUser loginUser = SecurityUtils.getInstance().getLoginUser();
String userId;
try {
userId = StpUtil.getLoginIdDefaultNull() == null ? Constants.SUPER_ADMIN_ID : StpUtil.getLoginIdDefaultNull().toString();
} catch (SaTokenException e) {
userId = Constants.SUPER_ADMIN_ID;
}
//设置 account 被更新时的一些默认数据
baseEntity.setUpdateTime(LocalDateTime.now());
baseEntity.setUpdateUserId(null == loginUser ? "1" : loginUser.getUserId());
baseEntity.setUpdateUserId(userId);
}
}

View File

@ -1,8 +1,7 @@
package com.cpop.core.base.entity;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
@ -10,7 +9,6 @@ import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.util.Assert;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
@ -19,42 +17,52 @@ import java.nio.charset.StandardCharsets;
* @Author: DB
*/
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
private ObjectMapper objectMapper = new ObjectMapper();
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private final Class<T> clazz;
static {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
//如果遇到反序列化autoType is not support错误请添加并修改一下包名到bean文件路径
// ParserConfig.getGlobalInstance().addAccept("com.xxxxx.xxx");
}
/**
* 构造器.
*
* @param clazz cls
*/
public FastJson2JsonRedisSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
/**
* 序列化.
*
* @param t object to serialize. Can be {@literal null}.
* @return es
* @throws SerializationException e
*/
@Override
public byte[] serialize(T t) throws SerializationException {
if (t == null) {
return new byte[0];
}
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
return com.alibaba.fastjson2.JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(StandardCharsets.UTF_8);
}
/**
* 反序列化.
*
* @param bytes object binary representation. Can be {@literal null}.
* @return es
* @throws SerializationException e
*/
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length <= 0) {
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
String str = new String(bytes, StandardCharsets.UTF_8);
return JSON.parseObject(str, clazz);
}
public void setObjectMapper(ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "'objectMapper' must not be null");
this.objectMapper = objectMapper;
}
protected JavaType getJavaType(Class<?> clazz) {

View File

@ -3,6 +3,7 @@ package com.cpop.core.base.entity;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serial;
import java.io.Serializable;
import java.util.Set;
@ -15,8 +16,14 @@ import java.util.Set;
@Accessors(chain = true)
public class LoginSuccess implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private String id;
/**
* 用户id
*/
@ -31,4 +38,10 @@ public class LoginSuccess implements Serializable {
* 权限
*/
private Set<String> role;
public LoginSuccess(String id, String userId, String token) {
this.id = id;
this.userId = userId;
this.token = token;
}
}

View File

@ -1,156 +0,0 @@
package com.cpop.core.base.entity;
import com.alibaba.fastjson.annotation.JSONField;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.enums.UserType;
import com.cpop.core.base.table.SysUser;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Set;
/**
* 登录用户身份权限
*
* @author DB
*/
@Data
@Accessors(chain = true)
public class LoginUser implements UserDetails {
/**
* 用户ID
*/
private String userId;
/**
* 用户名
*/
private String userName;
/**
* 用户唯一标识
*/
private String identification;
/**
* 登录时间
*/
private Long loginTime = System.currentTimeMillis();
/**
* 过期时间
*/
private Long expireTime;
/**
* 登录IP地址
*/
private String ipAddr;
/**
* 登录地点
*/
private String loginLocation;
/**
* 权限列表
*/
private Set<String> permissions;
/**
* 用户信息
*/
private SysUser user;
/**
* 消息
*/
private String msg;
/**
* 登录状态
*/
private Boolean status;
/**
* 用户类型
*/
private UserType userType = UserType.OAM_USER;
public LoginUser() {
}
public LoginUser(SysUser user,String identification, Set<String> permissions) {
this.user = user;
this.identification = identification;
this.permissions = permissions;
}
public LoginUser(String userId, SysUser user, Set<String> permissions) {
this.userId = userId;
this.user = user;
this.permissions = permissions;
}
@JSONField(serialize = false)
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
if (StringUtils.isBlank(this.userName)){
return user.getUserName();
}else {
return this.userName;
}
}
/**
* 账户是否未过期,过期无法验证
*/
@JSONField(serialize = false)
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 指定用户是否解锁,锁定的用户无法进行身份验证
*/
@JSONField(serialize = false)
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
*/
@JSONField(serialize = false)
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* 是否可用 ,禁用的用户不能身份验证
*/
@JSONField(serialize = false)
@Override
public boolean isEnabled() {
return true;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
//根据自定义逻辑来返回用户权限如果用户权限返回空或者和拦截路径对应权限不同验证不通过;自定义权限注解此处设定为null
return null;
}
}

View File

@ -1,115 +0,0 @@
package com.cpop.core.base.entity;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
/**
* @author DB
* @since 2023-12-10 9:35
* @version 1.0.0
*
* 负责将InputStream转换MultipartFile,可以少引一个jar包,本来用的是spring-test-4.3.9中的MockMultipartFile,直接提取出来使用
*/
public class MultipartFileDto implements MultipartFile {
private final String name;
private String originalFilename;
private String contentType;
private final byte[] content;
/**
* Create a new MultipartFileDto with the given content.
* @param name the name of the file
* @param content the content of the file
*/
public MultipartFileDto(String name, byte[] content) {
this(name, "", null, content);
}
/**
* Create a new MultipartFileDto with the given content.
* @param name the name of the file
* @param contentStream the content of the file as stream
* @throws IOException if reading from the stream failed
*/
public MultipartFileDto(String name, InputStream contentStream) throws IOException {
this(name, "", null, FileCopyUtils.copyToByteArray(contentStream));
}
/**
* Create a new MultipartFileDto with the given content.
* @param name the name of the file
* @param originalFilename the original filename (as on the client's machine)
* @param contentType the content type (if known)
* @param content the content of the file
*/
public MultipartFileDto(String name, String originalFilename, String contentType, byte[] content) {
this.name = name;
this.originalFilename = (originalFilename != null ? originalFilename : "");
this.contentType = contentType;
this.content = (content != null ? content : new byte[0]);
}
/**
* Create a new MultipartFileDto with the given content.
* @param name the name of the file
* @param originalFilename the original filename (as on the client's machine)
* @param contentType the content type (if known)
* @param contentStream the content of the file as stream
* @throws IOException if reading from the stream failed
*/
public MultipartFileDto(String name, String originalFilename, String contentType, InputStream contentStream)
throws IOException {
this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream));
}
@Override
public String getName() {
return this.name;
}
@Override
public String getOriginalFilename() {
return this.originalFilename;
}
@Override
public String getContentType() {
return this.contentType;
}
@Override
public boolean isEmpty() {
return (this.content.length == 0);
}
@Override
public long getSize() {
return this.content.length;
}
@Override
public byte[] getBytes() throws IOException {
return this.content;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(this.content);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
FileCopyUtils.copy(this.content, dest);
}
}

View File

@ -1,12 +1,16 @@
package com.cpop.core.base.entity;
import com.cpop.common.utils.StringUtils;
import cn.hutool.core.util.StrUtil;
import lombok.Getter;
/**
* 分页数据
*
* @author DB
* @version 1.0.0
* @since 2024/05/23
*/
@Getter
public class PageDomain {
/**
* 当前记录起始索引
@ -16,6 +20,7 @@ public class PageDomain {
/**
* 每页显示记录数
*/
private Integer pageSize;
/**
@ -33,33 +38,50 @@ public class PageDomain {
*/
private Boolean reasonable = true;
/**
* 获得订单
*
* @return {@link String }
* @author DB
* @since 2024/05/23
*/
public String getOrderBy() {
if (StringUtils.isEmpty(orderByColumn)) {
if (StrUtil.isEmpty(orderByColumn)) {
return "";
}
return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc;
}
public Integer getPageNum() {
return page;
return StrUtil.toUnderlineCase(orderByColumn) + " " + isAsc;
}
/**
* 设置页码
*
* @param pageNum 页面num
* @author DB
* @since 2024/05/23
*/
public void setPageNum(Integer pageNum) {
this.page = pageNum;
}
public Integer getPageSize() {
return pageSize;
}
/**
* 设置页面大小
*
* @param pageSize 页面大小
* @author DB
* @since 2024/05/23
*/
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public String getOrderByColumn() {
return orderByColumn;
}
/**
* 按列设置顺序
*
* @param orderByColumn 按列排序
* @author DB
* @since 2024/05/23
*/
public void setOrderByColumn(String orderByColumn) {
this.orderByColumn = orderByColumn;
}
@ -69,11 +91,11 @@ public class PageDomain {
}
public Boolean getBoolAsc() {
return StringUtils.equals(isAsc, "asc");
return StrUtil.equals(isAsc, "asc");
}
public void setIsAsc(String isAsc) {
if (StringUtils.isNotEmpty(isAsc)) {
if (StrUtil.isNotEmpty(isAsc)) {
// 兼容前端排序类型
if ("ascending".equals(isAsc)) {
isAsc = "asc";
@ -84,13 +106,13 @@ public class PageDomain {
}
}
public Boolean getReasonable() {
if (StringUtils.isNull(reasonable)) {
return Boolean.TRUE;
}
return reasonable;
}
/**
* 设置合理
*
* @param reasonable 合理
* @author DB
* @since 2024/05/23
*/
public void setReasonable(Boolean reasonable) {
this.reasonable = reasonable;
}

View File

@ -1,20 +0,0 @@
package com.cpop.core.base.entity;
/**
* 权限组
*/
public class Permission {
/**
* 权限
*/
private String permission;
public String getPermission() {
return permission;
}
public void setPermission(String permission) {
this.permission = permission;
}
}

View File

@ -1,7 +1,9 @@
package com.cpop.core.base;
package com.cpop.core.base.entity;
import com.cpop.common.constant.Constants;
import com.cpop.core.constant.Constants;
import java.io.Serial;
import java.io.Serializable;
/**
@ -11,6 +13,7 @@ import java.io.Serializable;
*/
public class R<T> implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**

View File

@ -1,48 +0,0 @@
package com.cpop.core.base.entity.loginInfo;
import com.cpop.core.base.enums.SourceType;
import com.cpop.core.base.table.SysUser;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @author DB
* @createTime 2023/10/19 13:10
* @description 商城管理员工登陆信息
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public class MallStaffLoginInfo extends SysUser {
/**
* 员工id(mallStaffId)
*/
private String id;
/**
* 姓名
*/
private String name;
/**
* 用户id
*/
private String userId;
/**
* 角色id
*/
private String roleId;
/**
* 品牌id
*/
private String brandId;
/**
* 用户来源
*/
private SourceType sourceType;
}

View File

@ -1,58 +0,0 @@
package com.cpop.core.base.entity.loginInfo;
import com.cpop.core.base.enums.SourceType;
import com.cpop.core.base.table.SysUser;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @author DB
* @createTime 2023/10/24 9:16
* @description 小程序登陆用户信息
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public class MiniUserLoginInfo extends SysUser {
/**
* 小程序用户id
*/
private String id;
/**
* 小程序openId
*/
private String openId;
/**
* 小程序appid
*/
private String appId;
/**
* 用户id
*/
private String userId;
/**
* 品牌id
*/
private String brandId;
/**
* 昵称
*/
private String nickName;
/**
* 头像
*/
private String avatar;
/**
* 小程序用户来源
*/
private SourceType sourceType;
}

View File

@ -1,8 +1,11 @@
package com.cpop.common.enums;
package com.cpop.core.base.enums;
import lombok.Getter;
/**
* @author LOST.yuan
*/
@Getter
public enum ErrorCodeEnum {
/** jwt凭据已过期 */
@ -67,14 +70,6 @@ public enum ErrorCodeEnum {
this.info = info;
}
public Integer getCode() {
return code;
}
public String getInfo() {
return info;
}
public static ErrorCodeEnum codeOf(Integer code) {
for (ErrorCodeEnum value : values()) {
if (value.getCode().equals(code)) {

View File

@ -17,66 +17,7 @@ public enum OperationLogEnum {
* 系统用户退出登录
*/
SYSTEM_LOGOUT(1, "i18n_operationLog_systemLogout", "SystemLoginModel", 6, 4),
/**
* 更新系统配置
*/
UPDATE_OAM_CONFIG(2, "i18n_operationLog_systemLogout", "SystemLoginModel", 5, 3),
//10-15 OAM菜单管理
/**
* 新增OAM菜单
*/
INSERT_OAM_MENU(10, "i18n_operationLog_insertOamMenu", "OamMenuModel", 5, 3),
/**
* 修改OAM菜单
*/
UPDATE_OAM_MENU(11, "i18n_operationLog_updateOamMenu", "OamMenuModel", 4, 3),
/**
* 删除OAM菜单
*/
REMOVE_OAM_MENU(12, "i18n_operationLog_removeOamMenu", "OamMenuModel", 4, 2),
//16-20 角色管理
/**
* 新增系统角色
*/
INSERT_OAM_ROLE(16, "i18n_operationLog_insertOamRole", "OamRoleModel", 5, 3),
/**
* 修改系统角色
*/
UPDATE_OAM_ROLE(17, "i18n_operationLog_updateOamRole", "OamRoleModel", 4, 3),
/**
* 删除系统角色
*/
REMOVE_OAM_ROLE(18, "i18n_operationLog_removeOamRole", "OamRoleModel", 4, 2),
//21-25 部门管理
/**
* 新增系统部门
*/
INSERT_OAM_DEPT(21, "i18n_operationLog_insertOamDept", "OamDeptModel", 5, 3),
/**
* 修改系统部门
*/
UPDATE_OAM_DEPT(22, "i18n_operationLog_updateOamDept", "OamDeptModel", 4, 3),
/**
* 删除系统部门
*/
REMOVE_OAM_DEPT(23, "i18n_operationLog_removeOamDept", "OamDeptModel", 4, 2),
//26-30 系统员工管理
/**
* 新增员工
*/
INSERT_OAM_STAFF(26, "i18n_operationLog_insertOamStaff", "OamStaffModel", 6, 4),
/**
* 修改系统用户
*/
UPDATE_OAM_STAFF(27, "i18n_operationLog_updateOamStaff", "OamStaffModel", 6, 4),
/**
* 删除系统用户
*/
REMOVE_OAM_STAFF(28, "i18n_operationLog_removeOamStaff", "OamStaffModel", 5, 3),
/**
* 修改系统用户密码
*/
MODIFY_OAM_STAFF_PASSWORD(29, "i18n_operationLog_updateOamStaffPassword", "OamStaffModel", 6, 4),
;
/**

View File

@ -1,27 +0,0 @@
package com.cpop.core.base.enums;
import lombok.Getter;
@Getter
public enum SourceType {
/**
* 通用
*/
COMMON("Common"),
/**
* 果酱
*/
JAMBOX("Jambox");
private String name;
SourceType(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -1,10 +1,5 @@
package com.cpop.core.base.enums;
import com.cpop.core.strategy.login.LoginStrategy;
import com.cpop.core.strategy.login.MallLoginStrategy;
import com.cpop.core.strategy.login.MiniLoginStrategy;
import com.cpop.core.strategy.login.OamLoginStrategy;
import com.cpop.core.utils.SpringUtils;
import lombok.Getter;
/**
@ -17,15 +12,8 @@ public enum UserType {
/**
* oam系统员工
*/
OAM_USER(0, "oam:loginUser:", SpringUtils.getBean(OamLoginStrategy.class)),
/**
* 小程序用户
*/
MINI_USER(1, "mini:loginUser:", SpringUtils.getBean(MiniLoginStrategy.class)),
/**
* 商城系统员工
*/
MALL_USER(2, "mall:loginUser:",SpringUtils.getBean(MallLoginStrategy.class));
OAM_USER(0, "oam:loginUser:"),
;
/**
* code
@ -37,12 +25,9 @@ public enum UserType {
*/
private final String key;
private final LoginStrategy strategy;
UserType(Integer code, String key, LoginStrategy strategy) {
UserType(Integer code, String key) {
this.code = code;
this.key = key;
this.strategy = strategy;
}
}

View File

@ -1,15 +1,20 @@
package com.cpop.core.base.exception;
import com.cpop.common.utils.StringUtils;
import cn.hutool.core.util.StrUtil;
import com.cpop.core.utils.MessageUtils;
import lombok.Getter;
import java.io.Serial;
/**
* 基础异常
*
* @author DB
*/
@Getter
public class BaseException extends RuntimeException {
@Serial
private static final long serialVersionUID = 1L;
/**
@ -58,7 +63,7 @@ public class BaseException extends RuntimeException {
@Override
public String getMessage() {
String message = null;
if (!StringUtils.isEmpty(code)) {
if (!StrUtil.isEmpty(code)) {
message = MessageUtils.message(code, args);
}
if (message == null) {
@ -67,19 +72,4 @@ public class BaseException extends RuntimeException {
return message;
}
public String getModule() {
return module;
}
public String getCode() {
return code;
}
public Object[] getArgs() {
return args;
}
public String getDefaultMessage() {
return defaultMessage;
}
}

View File

@ -1,26 +0,0 @@
package com.cpop.core.base.exception;
import org.springframework.security.core.AuthenticationException;
/**
* @author: DB
* @Date: 2023/08/24/18:10
* @Description: 自定义认证失败异常
*/
public class CpopAuthenticationException extends AuthenticationException {
private Object params;
public CpopAuthenticationException(String msg) {
super(msg);
}
public CpopAuthenticationException(String msg, Object params) {
super(msg);
this.params = params;
}
public Object getParams() {
return params;
}
}

View File

@ -23,7 +23,7 @@ import java.io.Serializable;
@AllArgsConstructor
@Accessors(chain = true)
@Table(value = "cp_sys_config", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
public class SysConfig extends BaseEntity implements Serializable {
public class Config extends BaseEntity implements Serializable {
/**
* 参数键

View File

@ -24,7 +24,7 @@ import java.io.Serializable;
@AllArgsConstructor
@Accessors(chain = true)
@Table(value = "cp_sys_operation_log", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
public class SysOperationLog extends BaseEntity implements Serializable {
public class OperationLog extends BaseEntity implements Serializable {
/**
* ID

View File

@ -3,10 +3,10 @@ package com.cpop.core.base.table;
import com.cpop.core.base.entity.BaseEntity;
import com.cpop.core.base.entity.BaseInsertListener;
import com.cpop.core.base.entity.BaseUpdateListener;
import com.cpop.core.base.enums.UserType;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import com.cpop.core.base.enums.UserType;
import lombok.*;
import lombok.experimental.Accessors;
@ -25,7 +25,7 @@ import java.io.Serializable;
@AllArgsConstructor
@Accessors(chain = true)
@Table(value = "cp_sys_user", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
public class SysUser extends BaseEntity implements Serializable {
public class User extends BaseEntity implements Serializable {
/**
* 主键
@ -36,7 +36,7 @@ public class SysUser extends BaseEntity implements Serializable {
/**
* 用户名
*/
private String userName;
private String username;
/**
* 密码
@ -51,7 +51,7 @@ public class SysUser extends BaseEntity implements Serializable {
/**
* 昵称
*/
private String nickName;
private String nickname;
/**
* 邮箱
@ -61,7 +61,7 @@ public class SysUser extends BaseEntity implements Serializable {
/**
* 手机号
*/
private String phoneNumber;
private String phone;
/**
* 性别(0:;1:)
@ -91,7 +91,7 @@ public class SysUser extends BaseEntity implements Serializable {
/**
* 用户类型
*/
private String userType;
private UserType userType;
/**
* 逻辑删除0否1是

View File

@ -45,18 +45,16 @@ public class AsyncScheduledTaskConfig {
executor.setWaitForTasksToCompleteOnShutdown(false);
//设置线程池中任务的等待时间如果超过这个时候还没有销毁就强制销毁以确保应用最后能够被关闭而不是阻塞住
executor.setAwaitTerminationSeconds(config.getAwaitTerminationSeconds());
/**
* 拒绝处理策略
* CallerRunsPolicy()交由调用方线程运行比如 main 线程
* AbortPolicy()直接抛出异常
* DiscardPolicy()直接丢弃
* DiscardOldestPolicy()丢弃队列中最老的任务
* 特殊说明
* 1. 这里演示环境拒绝策略咱们采用抛出异常
* 2.真实业务场景会把缓存队列的大小会设置大一些
* 如果提交的任务数量超过最大线程数量或将任务环缓存到本地redismysql中,保证消息不丢失
* 3.如果项目比较大的话异步通知种类很多的话建议采用MQ做异步通知方案
*/
//拒绝处理策略
//CallerRunsPolicy()交由调用方线程运行比如 main 线程
//AbortPolicy()直接抛出异常
//DiscardPolicy()直接丢弃
//DiscardOldestPolicy()丢弃队列中最老的任务
//特殊说明
//1. 这里演示环境拒绝策略咱们采用抛出异常
//2.真实业务场景会把缓存队列的大小会设置大一些
//如果提交的任务数量超过最大线程数量或将任务环缓存到本地redismysql中,保证消息不丢失
//3.如果项目比较大的话异步通知种类很多的话建议采用MQ做异步通知方案
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
//线程初始化
executor.initialize();

View File

@ -0,0 +1,29 @@
package com.cpop.core.config;
import com.cpop.core.service.ConfigService;
import com.cpop.core.strategy.dataSourceSharding.CpopDataSourceShardingStrategy;
import com.cpop.core.utils.SpringUtils;
import com.mybatisflex.core.datasource.DataSourceManager;
import jakarta.annotation.PostConstruct;
import org.springframework.context.annotation.Configuration;
/**
* 核心初始化文件
* @author DB
* @version 1.0.0
* @since 2024-02-05 9:39
*/
@Configuration
public class CoreInitConfig {
/**
* 初始化
*/
@PostConstruct
public void init() {
//设置数据源分片策略
DataSourceManager.setDataSourceShardingStrategy(new CpopDataSourceShardingStrategy());
//初始化系统配置信息
SpringUtils.getBean(ConfigService.class).loadingConfigCache();
}
}

View File

@ -1,13 +1,32 @@
package com.cpop.core.config;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.RSA;
import com.cpop.core.base.exception.UtilException;
import lombok.Data;
import lombok.Getter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Key;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
/**
* 读取项目相关配置
*
* @author DB
*/
@Getter
@Component
@ConfigurationProperties(prefix = "cpop")
public class CpopConfig {
@ -29,20 +48,13 @@ public class CpopConfig {
/**
* 验证码类型
*/
@Getter
private static String captchaType;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@ -55,10 +67,6 @@ public class CpopConfig {
CpopConfig.profile = profile;
}
public static String getCaptchaType() {
return captchaType;
}
public void setCaptchaType(String captchaType) {
CpopConfig.captchaType = captchaType;
}
@ -90,5 +98,220 @@ public class CpopConfig {
public String getUploadPath() {
return getProfile() + "/upload";
}
/**
* jwt
*/
private Jwt jwt;
/**
* jwt设置
*
* @param jwt jwt
* @author DB
* @since 2024/05/23
*/
public void setJwt(Jwt jwt) {
this.jwt = jwt;
}
/**
* jwt
*
* @author DB
* @version 1.0.0
* @since 2024/05/23
*/
@Data
public static class Jwt {
/**
* 白名单
*/
private String whiteList;
}
/**
* 网关配置
*/
private Gateway gateway;
/**
* 设置网关
*
* @param gateway 网关
* @author DB
* @since 2024/05/23
*/
public void setGateway(Gateway gateway) {
this.gateway = gateway;
}
/**
* 网关
*
* @author DB
* @version 1.0.0
* @since 2024/05/23
*/
@Data
public static class Gateway {
/**
* rsa密钥对
*/
private RsaKeypair rsaKeypair;;
/**
* rsa密钥对
*
* @author DB
* @version 1.0.0
* @since 2024/05/23
*/
@Data
public static class RsaKeypair {
/**
* 算法
*/
private String algorithm;
/**
* 关键尺寸
*/
private Integer keySize;
/**
* 公钥文件
*/
private String publicKeyFile;
/**
* 私钥文件
*/
private String privateKeyFile;
}
}
/**
* 获取登录rsa
*
* @return {@link RSA }
* @author DB
* @since 2024/05/23
*/
public RSA getLoginRsa(){
//rsa解密
Gateway.RsaKeypair rsaKeypair = gateway.getRsaKeypair();
Map<String, String> keyPair = getKeyPair(rsaKeypair.getPublicKeyFile(), rsaKeypair.getPrivateKeyFile());
return SecureUtil.rsa(keyPair.get("privateKey"), keyPair.get("publicKey"));
}
/**
* 获取密钥对
*
* @param publicKeyFile 公钥文件
* @param privateKeyFile 私钥文件
* @return {@link Map }<{@link String }, {@link String }>
* @author DB
* @since 2024/05/23
*/
private Map<String, String> getKeyPair(String publicKeyFile, String privateKeyFile){
Map<String, String> keyPairMap = new HashMap<>(2);
File publicFile = new File(publicKeyFile);
File privateFile = new File(privateKeyFile);
//判断是否存在公钥和私钥文件
if (!publicFile.exists() || !privateFile.exists()) {
generateKeyPairToFiles(publicKeyFile, privateKeyFile);
}
ObjectInputStream oisPublic = null;
ObjectInputStream oisPrivate = null;
Key publicKey = null;
Key privateKey = null;
try {
oisPublic = new ObjectInputStream(Files.newInputStream(Paths.get(publicKeyFile)));
oisPrivate = new ObjectInputStream(Files.newInputStream(Paths.get(privateKeyFile)));
publicKey = (Key) oisPublic.readObject();
privateKey = (Key) oisPrivate.readObject();
byte[] publicKeyBytes = publicKey.getEncoded();
byte[] privateKeyBytes = privateKey.getEncoded();
String publicKeyBase64 = Base64.getEncoder().encodeToString(publicKeyBytes);
String privateKeyBase64 = Base64.getEncoder().encodeToString(privateKeyBytes);
//公钥字符串
keyPairMap.put("publicKey", publicKeyBase64);
//私钥字符串
keyPairMap.put("privateKey", privateKeyBase64);
} catch (IOException | ClassNotFoundException e) {
throw new UtilException(e.getMessage());
} finally {
try {
assert oisPrivate != null;
oisPrivate.close();
oisPublic.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return keyPairMap;
}
/**
* 生成文件密钥对
*
* @param publicKeyFile 公钥文件
* @param privateKeyFile 私钥文件
* @author DB
* @since 2024/05/23
*/
private void generateKeyPairToFiles(String publicKeyFile, String privateKeyFile) {
ObjectOutputStream oosPublicKey = null;
ObjectOutputStream oosPrivateKey = null;
try {
Map<String, Key> keyPairMap = generateKeyPair();
Key publicKey = keyPairMap.get("publicKey");
Key privateKey = keyPairMap.get("privateKey");
oosPublicKey = new ObjectOutputStream(Files.newOutputStream(Paths.get(publicKeyFile)));
oosPrivateKey = new ObjectOutputStream(Files.newOutputStream(Paths.get(privateKeyFile)));
oosPublicKey.writeObject(publicKey);
oosPrivateKey.writeObject(privateKey);
} catch (NoSuchAlgorithmException | IOException e) {
throw new UtilException(e.getMessage());
} finally {
try {
//清空缓存关闭文件输出流
assert oosPublicKey != null;
oosPublicKey.close();
assert oosPrivateKey != null;
oosPrivateKey.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 生成密钥对
*
* @return {@link Map }<{@link String }, {@link Key }>
* @throws NoSuchAlgorithmException 生成失败异常
* @author DB
* @since 2024/05/23
*/
private Map<String, Key> generateKeyPair() throws NoSuchAlgorithmException {
KeyPair keyPair = SecureUtil.generateKeyPair(gateway.getRsaKeypair().getAlgorithm(), gateway.getRsaKeypair().getKeySize());
//得到公钥
Key publicKey = keyPair.getPublic();
//得到私钥
Key privateKey = keyPair.getPrivate();
Map<String, Key> keyPairMap = new HashMap<>();
keyPairMap.put("publicKey", publicKey);
keyPairMap.put("privateKey", privateKey);
return keyPairMap;
}
}

View File

@ -1,59 +0,0 @@
package com.cpop.core.config;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.filter.XssFilter;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.DispatcherType;
import java.util.HashMap;
import java.util.Map;
/**
* Filter配置
*
* @author DB
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "xss")
public class FilterConfig {
/**
* 排除链接多个用逗号分隔
*/
private String excludes;
/**
* 匹配链接
*/
private String urlPatterns;
/**
* @Description: xss过滤器
* @param
* @return: FilterRegistrationBean
* @Author: DB
* @Date: 2023/4/17 9:17
**/
@SuppressWarnings({"rawtypes", "unchecked"})
@Bean
@ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
public FilterRegistrationBean xssFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setDispatcherTypes(DispatcherType.REQUEST);
registration.setFilter(new XssFilter());
registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
registration.setName("xssFilter");
registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
Map<String, String> initParameters = new HashMap<String, String>();
initParameters.put("excludes", excludes);
registration.setInitParameters(initParameters);
return registration;
}
}

View File

@ -1,38 +0,0 @@
package com.cpop.core.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author DB
* @Description: 生成密钥对的配置文件
* @create: 2023-08-04 23:06
*/
@Data
@Component
@ConfigurationProperties(prefix = "cpop.gateway.rsa-keypair")
public class GenerateKeyPairConfig {
/**
* 加密方式
*/
private String algorithm;
/**
* 初始化大小
*/
private Integer keySize;
/**
* 公钥文件
*/
private String publicKeyFile;
/**
* 私钥文件
*/
private String privateKeyFile;
}

View File

@ -1,15 +1,28 @@
package com.cpop.core.config;
import cn.hutool.core.util.StrUtil;
import com.cpop.core.base.entity.FastJson2JsonRedisSerializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.util.Arrays;
/**
* redis配置
*
@ -19,9 +32,24 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
@Autowired
private RedisProperties redisProperties;
@Primary
@Bean(name = "redisConnectionFactory")
public RedisConnectionFactory wxOpenRedisConnectionFactory() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisProperties.getHost(), redisProperties.getPort());
configuration.setDatabase(redisProperties.getDatabase());
if (StrUtil.isNotBlank(redisProperties.getPassword())) {
configuration.setPassword(redisProperties.getPassword());
}
return new JedisConnectionFactory(configuration);
}
@Bean(name = "redisTemplate")
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(@Qualifier("redisConnectionFactory") RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
@ -35,6 +63,28 @@ public class RedisConfig extends CachingConfigurerSupport {
return template;
}
/**
* 缓存管理器
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager
.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory);
return builder.build();
}
@Bean
public KeyGenerator wiselyKeyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
Arrays.stream(params).map(Object::toString).forEach(sb::append);
return sb.toString();
};
}
@Bean
public DefaultRedisScript<Long> limitScript() {
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();

View File

@ -1,10 +1,13 @@
package com.cpop.core.config;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.time.Duration;
/**
* @author DB
* @version 1.0.0
@ -14,15 +17,13 @@ import org.springframework.web.client.RestTemplate;
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
// 创建一个 HttpComponentsClientHttpRequestFactory 客户端请求工厂实例
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
// 设置连接超时时间为 5
requestFactory.setConnectTimeout(5000);
restTemplateBuilder.setConnectTimeout(Duration.ofMillis(5000));
// 设置读取超时时间为 10
requestFactory.setReadTimeout(10000);
restTemplateBuilder.setReadTimeout(Duration.ofMillis(10000));
// 使用 HttpComponentsClientHttpRequestFactory 客户端请求工厂实例创建 RestTemplate 实例
return new RestTemplate(requestFactory);
return restTemplateBuilder.build();
}
}

View File

@ -0,0 +1,136 @@
package com.cpop.core.config;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.jwt.StpLogicJwtForSimple;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import com.cpop.core.constant.Constants;
import com.cpop.core.filter.RepeatableFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Arrays;
import java.util.Collections;
/**
* Sa令牌配置
*
* @author DB
* @version 1.0.0
* @since 2023-08-05 8:01
*/
@Configuration
@RequiredArgsConstructor
public class SaTokenConfigure implements WebMvcConfigurer {
/**
* jambox配置
*/
@Autowired(required = false)
private CpopConfig cpopConfig;
/**
* 获取servlet过滤器
*
* @return {@link SaServletFilter }
* @author DB
* @since 2024/05/23
*/
@Bean
public SaServletFilter getSaServletFilter() {
RepeatableFilter repeatableFilter = new RepeatableFilter();
repeatableFilter
// 指定 拦截路由 放行路由
//.addInclude("/**").addExclude(jamboxConfig.getJwt().getWhiteList().split(","))
// 认证函数: 每次请求执行
//.setAuth(obj -> {
// 登录认证 -- 拦截所有路由并排除/user/doLogin 用于开放登录
//SaRouter.match("/**", "/user/doLogin", StpUtil::checkLogin);
// 更多拦截处理方式请参考路由拦截式鉴权章节 */
//})
// 异常处理函数每次认证函数发生异常时执行此函数
//.setError(e -> SaResult.error(e.getMessage()))
// 前置函数在每次认证函数之前执行BeforeAuth 不受 includeList excludeList 的限制所有请求都会进入
.setBeforeAuth(r -> {
// ---------- 设置一些安全响应头 ----------
SaHolder.getResponse()
// 服务器名称
.setServer("Jambox")
// 是否可以在iframe显示视图 DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
.setHeader("X-Frame-Options", "SAMEORIGIN")
// 是否启用浏览器默认XSS防护 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时停止渲染页面
.setHeader("X-XSS-Protection", "1; mode=block")
// 禁用浏览器内容嗅探
.setHeader("X-Content-Type-Options", "nosniff")
;
});
return repeatableFilter;
}
/**
* 注册 Sa-Token 拦截器打开注解式鉴权功能
*
* @param registry 拦截器注册
* @author DB
* @since 2024/3/20
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册 Sa-Token 拦截器打开注解式鉴权功能
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
.addPathPatterns("/**")
.excludePathPatterns(Arrays.asList(cpopConfig.getJwt().getWhiteList().split(",")));
}
/**
* Sa-Token 整合 jwt (Simple 简单模式)
* @author DB
* @since 2024/3/20
* @return StpLogic
*/
@Bean
public StpLogic getStpLogicJwt() {
return new StpLogicJwtForSimple();
}
/**
* 配置跨源访问(CORS)
*/
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type"));
configuration.applyPermitDefaultValues();
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
/**
* 资源映射
*
* @param registry 注册
* @author DB
* @since 2023/5/27 13:57
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//本地文件上传路径
registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**")
.addResourceLocations("file:" + cpopConfig.getProfile() + "/");
}
}

View File

@ -1,215 +0,0 @@
package com.cpop.core.config;
import com.cpop.common.constant.Constants;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.filter.JwtAuthenticationFilter;
import com.cpop.core.filter.RepeatableFilter;
import com.cpop.core.gateway.miniProgram.MiniProgramAuthenticationFilter;
import com.cpop.core.gateway.miniProgram.MiniProgramAuthenticationProvider;
import com.cpop.core.gateway.sys.SysAuthenticationFilter;
import com.cpop.core.gateway.sys.SysAuthenticationProvider;
import com.cpop.core.handler.*;
import com.cpop.core.utils.JwtUtils;
import com.cpop.core.utils.PasswordEncoder;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Arrays;
import java.util.Collections;
/**
* @author DB
* @Description: Security配置中心
* @since 2023-08-05 8:01
*/
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableMethodSecurity
public class SecurityConfig implements WebMvcConfigurer {
@Autowired
private JwtLogoutSuccessHandler jwtLogoutSuccessHandler;
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
private JwtAccessDeniedHandler jwtAccessDeniedHandler;
@Autowired
private RepeatableFilter repeatableFilter;
@Autowired
private LoginSuccessHandler loginSuccessHandler;
@Autowired
private LoginFailureHandler loginFailureHandler;
@Autowired
private CpopConfig cpopConfig;
@Autowired
private JwtUtils jwtUtils;
/**
* Security过滤拦截配置
*
* @param http 请求
* @return SecurityFilterChain 认证过滤链
* @throws Exception 异常
*/
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors(AbstractHttpConfigurer::disable)
.csrf(AbstractHttpConfigurer::disable)
//登录配置(多登陆模式自定义成功与失败->现已注释)
/*.formLogin(formLogin -> {
formLogin.successHandler(loginSuccessHandler)
.failureHandler(loginFailureHandler);
})*/
//登出配置
.logout(logout -> logout.logoutSuccessHandler(jwtLogoutSuccessHandler))
//禁用session
.sessionManagement(sessionManagement -> {
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
})
//配置拦截规则
.authorizeHttpRequests(authorizeHttpRequests -> {
authorizeHttpRequests.antMatchers(StringUtils.split(jwtUtils.getWhiteList(), ",")).permitAll()
.anyRequest().authenticated();
})
//异常处理器
.exceptionHandling(exceptionHandling -> {
exceptionHandling.authenticationEntryPoint(jwtAuthenticationEntryPoint).accessDeniedHandler(jwtAccessDeniedHandler);
})
//自定义认证管理器
.authenticationManager(authenticationManager())
//流重复使用
.addFilterBefore(repeatableFilter, UsernamePasswordAuthenticationFilter.class)
// 添加 JWT 过滤器JWT 过滤器在退出认证过滤器之前
.addFilterBefore(authFilter(), LogoutFilter.class)
//.addFilterAt(oamLoginFilter(http.getSharedObject(AuthenticationManager.class)), UsernamePasswordAuthenticationFilter.class)
//系统登陆
.addFilterAt(sysAuthenticationFilter(http.getSharedObject(AuthenticationManager.class)), UsernamePasswordAuthenticationFilter.class)
//小程序认证
.addFilterAt(miniProgramAuthenticationFilter(http.getSharedObject(AuthenticationManager.class)), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
/**
* @Description: 小程序登陆认证方式(可自定义其他模式)
* @param authenticationManager 认证管理器
* @return MiniProgramAuthenticationFilter
* @author DB
* @Date: 2023/8/24 0024 10:43
*/
@Bean
public SysAuthenticationFilter sysAuthenticationFilter(AuthenticationManager authenticationManager) {
SysAuthenticationFilter filter = new SysAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager);
filter.setAuthenticationSuccessHandler(loginSuccessHandler);
filter.setAuthenticationFailureHandler(loginFailureHandler);
return filter;
}
@Bean
public SysAuthenticationProvider sysAuthenticationProvider() {
return new SysAuthenticationProvider();
}
/**
* @Description: 小程序登陆认证方式(可自定义其他模式)
* @param authenticationManager 认证管理器
* @return MiniProgramAuthenticationFilter
* @author DB
* @Date: 2023/8/24 0024 10:43
*/
@Bean
public MiniProgramAuthenticationFilter miniProgramAuthenticationFilter(AuthenticationManager authenticationManager) {
MiniProgramAuthenticationFilter filter = new MiniProgramAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager);
filter.setAuthenticationSuccessHandler(loginSuccessHandler);
filter.setAuthenticationFailureHandler(loginFailureHandler);
return filter;
}
@Bean
public MiniProgramAuthenticationProvider miniProgramAuthenticationProvider() {
return new MiniProgramAuthenticationProvider();
}
/**
* 获取AuthenticationManager认证管理器登录时认证使用
* @return AuthenticationManager
*/
@Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Arrays.asList(sysAuthenticationProvider(), miniProgramAuthenticationProvider()));
}
/**
* 密码明文加密方式配置
* @return PasswordEncoder
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new PasswordEncoder();
}
/**
* jwt 校验过滤器 http 头部 Authorization 字段读取 token 并校验
* @return JwtAuthenticationFilter
*/
@Bean
public JwtAuthenticationFilter authFilter() {
return new JwtAuthenticationFilter();
}
/**
* 配置跨源访问(CORS)
* @return CorsConfigurationSource
*/
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type"));
configuration.applyPermitDefaultValues();
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
/**
* @param registry 资源注册
* @Description: 资源映射
* @Author DB
* @Date: 2023/5/27 13:57
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//本地文件上传路径
registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**")
.addResourceLocations("file:" + cpopConfig.getProfile() + "/");
}
}

View File

@ -1,31 +0,0 @@
package com.cpop.core.config;
import com.cpop.common.utils.ServletUtils;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* 服务相关配置
*
* @author DB
*/
@Component
public class ServerConfig {
/**
* 获取完整的请求路径包括域名端口上下文访问路径
*
* @return 服务地址
*/
public String getUrl() {
HttpServletRequest request = ServletUtils.getRequest();
return getDomain(request);
}
public static String getDomain(HttpServletRequest request) {
StringBuffer url = request.getRequestURL();
String contextPath = request.getServletContext().getContextPath();
return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
}
}

View File

@ -1,4 +1,4 @@
package com.cpop.common.constant;
package com.cpop.core.constant;
/**
* 通用常量信息
@ -51,7 +51,7 @@ public interface Constants {
/**
* 通用失败标识
*/
Integer FAIL = 400;
Integer FAIL = 500;
/**
* 登录成功
@ -141,7 +141,7 @@ public interface Constants {
/**
* 参数管理 cache key
*/
String SYS_CONFIG_KEY = "sys_config:";
String CONFIG_KEY = "config:";
/**
* 字典管理 cache key
@ -166,8 +166,7 @@ public interface Constants {
/**
* 定时任务违规的字符
*/
String[] JOB_ERROR_STR = {"java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
"org.springframework.jndi"};
String[] JOB_ERROR_STR = {"java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml", "org.springframework.jndi"};
/**
* 超级管理员
@ -177,7 +176,12 @@ public interface Constants {
/**
* 超级管理员ID
*/
String SUPER_ADMIN_ID = "1";
String SUPER_ADMIN_ID = "100";
/**
* 超级身份id
*/
String SUPER_ROLE_ID = "100";
/**
* 超级管理员
@ -187,12 +191,12 @@ public interface Constants {
/**
* 所有权限
*/
String ALL_PERMISSION = "*:*:*";
String ALL_PERMISSION = "*";
/**
* 隐藏菜单
*/
String HIDE_MENU = "Menu";
String HIDE_MENU = "System,Menu,Dict";
/**
* 用户类型
@ -209,4 +213,75 @@ public interface Constants {
*/
String QRCODE_HEADER = "data:image/png;base64,";
/**
* 默认文件名长度
*/
Integer DEFAULT_FILE_NAME_LENGTH = 100;
/**
* 默认大小 50M
*/
Long DEFAULT_MAX_SIZE = 50L * 1024 * 1024;
/**
* png图像
*/
String IMAGE_PNG = "image/png";
/**
* jpg图像
*/
String IMAGE_JPG = "image/jpg";
/**
* jpeg图像
*/
String IMAGE_JPEG = "image/jpeg";
/**
* bmp图像
*/
String IMAGE_BMP = "image/bmp";
/**
* gif图像
*/
String IMAGE_GIF = "image/gif";
/**
* 映像扩展
*/
String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"};
/**
* flash扩展
*/
String[] FLASH_EXTENSION = {"swf", "flv"};
/**
* 媒体扩展
*/
String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
"asf", "rm", "rmvb"};
/**
* 视频扩展
*/
String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"};
/**
* 默认允许扩展
*/
String[] DEFAULT_ALLOWED_EXTENSION = {
// 图片
"bmp", "gif", "jpg", "jpeg", "png",
// word excel powerpoint
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
// 压缩文件
"rar", "zip", "gz", "bz2",
// 视频格式
"mp4", "avi", "rmvb",
// pdf
"pdf"};
}

View File

@ -1,4 +1,4 @@
package com.cpop.common.constant;
package com.cpop.core.constant;
/**
* 返回状态码
@ -85,4 +85,9 @@ public interface HttpStatus {
* 接口未实现
*/
int NOT_IMPLEMENTED = 501;
/**
* 校区过期
*/
int STORE_EXPIRE = 10000;
}

View File

@ -1,4 +1,4 @@
package com.cpop.common.constant;
package com.cpop.core.constant;
/**
* @author DB

View File

@ -1,163 +0,0 @@
package com.cpop.core.filter;
import com.alibaba.fastjson.JSONObject;
import com.cpop.common.constant.Constants;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.ip.IpUtils;
import com.cpop.core.base.R;
import com.cpop.core.base.entity.LoginUser;
import com.cpop.core.base.entity.loginInfo.MiniUserLoginInfo;
import com.cpop.core.base.enums.UserType;
import com.cpop.core.gateway.miniProgram.MiniProgramAuthenticationToken;
import com.cpop.core.gateway.sys.SysAuthenticationToken;
import com.cpop.core.service.CoreService;
import com.cpop.core.service.RedisService;
import com.cpop.core.service.impl.OamStaffDetailsServiceImpl;
import com.cpop.core.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import org.springframework.lang.NonNullApi;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* @author: DB
* @date: 2022-09-25 16:34
* @Description: jwt认证过滤器
*/
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtUtils jwtUtils;
@Autowired
private OamStaffDetailsServiceImpl oamStaffDetailsService;
@Autowired
private CoreService coreService;
@Autowired
private RedisService redisService;
@Override
protected void doFilterInternal(HttpServletRequest request, @NonNull HttpServletResponse response,@NonNull FilterChain chain) throws IOException, ServletException {
String jwt = request.getHeader(jwtUtils.getHeader());
// 这里如果没有jwt继续往后走因为后面还有鉴权管理器等去判断是否拥有身份凭证所以是可以放行的
// 没有jwt相当于匿名访问若有一些接口是需要权限的则不能访问这些接口
if (StringUtils.isEmpty(jwt)) {
chain.doFilter(request, response);
return;
}
Jws<Claims> jws = jwtUtils.getClaimsByToken(jwt);
if (jws == null) {
returnJwtException(response,"token 失效");
return;
}
Claims claim = jws.getBody();
if (claim == null) {
returnJwtException(response,"token 异常");
return;
}
if (jwtUtils.isTokenExpired(claim)) {
returnJwtException(response,"token 已过期");
return;
}
//当前用户类型下唯一
String identification = claim.getSubject();
String username = jws.getHeader().get(Constants.USERNAME).toString();
UserType userType = UserType.valueOf(jws.getHeader().get(Constants.USER_TYPE).toString());
//从缓存中获取
JSONObject jsonObject = redisService.getCacheObject(userType.getKey() + identification);
LoginUser loginUser;
if (null == jsonObject){
loginUser = multipleLoadUser(userType, username);
//存入缓存
redisService.setCacheObject(userType.getKey() + loginUser.getIdentification(), loginUser);
} else {
loginUser = jsonObject.toJavaObject(LoginUser.class);
}
//获取当前请求ip
loginUser.setIpAddr(IpUtils.getIpAddr(request));
multipleAuth(loginUser);
chain.doFilter(request, response);
}
/**
* jwt异常直接返回
* @param response 响应
* @param msg 错误信息
*/
private void returnJwtException(HttpServletResponse response,String msg) throws IOException {
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
ServletOutputStream outputStream = response.getOutputStream();
R<String> result = R.fail(401, msg);
outputStream.write(JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8));
outputStream.flush();
outputStream.close();
}
/**
* @descriptions 多种获取用户信息
* @author DB
* @date 2023/09/11 13:49
* @param userType 用户类型
* @param username 用户名
* @return com.pupu.core.base.entity.LoginUser
*/
private LoginUser multipleLoadUser(UserType userType, String username) {
LoginUser loginUser = null;
switch (userType) {
//系统登陆
case OAM_USER:
case MALL_USER:
loginUser = coreService.loadUserByUsername(username, userType);
break;
case MINI_USER:
// 获取用户的权限等信息
loginUser = coreService.loadUserByPhone(username, userType, null);
break;
default:
}
return loginUser;
}
/**
* @Description: 多种认证方式
* @param loginUser 登陆用户信息
* @author DB
* @Date: 2023/8/24 0024 17:12
*/
private void multipleAuth(LoginUser loginUser) {
switch (loginUser.getUserType()) {
case OAM_USER:
case MALL_USER:
//构建通用系统用户登陆
// 构建UsernamePasswordAuthenticationToken,这里密码为null是因为提供了正确的JWT,实现自动登录
SysAuthenticationToken sysAuthenticationToken = new SysAuthenticationToken(loginUser.getIdentification(), loginUser, null);
SecurityContextHolder.getContext().setAuthentication(sysAuthenticationToken);
break;
case MINI_USER:
// MiniProgramAuthenticationToken,实现自动登录
MiniProgramAuthenticationToken miniProgramAuthenticationToken = new MiniProgramAuthenticationToken(loginUser.getIdentification(), loginUser, null);
SecurityContextHolder.getContext().setAuthentication(miniProgramAuthenticationToken);
break;
default:
}
}
}

View File

@ -1,14 +1,17 @@
package com.cpop.core.filter;
import com.cpop.common.utils.StringUtils;
import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.router.SaRouter;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
;
/**
* Repeatable 过滤器
@ -16,17 +19,30 @@ import java.io.IOException;
* @author DB
*/
@Component
public class RepeatableFilter implements Filter {
public class RepeatableFilter extends SaServletFilter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
this.beforeAuth.run((Object)null);
SaRouter.match(this.includeList).notMatch(this.excludeList).check((r) -> {
this.auth.run((Object)null);
});
} catch (StopMatchException ignored) {
} catch (Throwable var7) {
String result = var7 instanceof BackResultException ? var7.getMessage() : String.valueOf(this.error.run(var7));
if (response.getContentType() == null) {
response.setContentType("text/plain; charset=utf-8");
}
response.getWriter().print(result);
}
ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
if (request instanceof HttpServletRequest && StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
}
if (null == requestWrapper) {

View File

@ -1,16 +1,16 @@
package com.cpop.core.filter;
import com.cpop.common.utils.http.HttpHelper;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import java.io.*;
import java.nio.charset.StandardCharsets;
/**
@ -18,6 +18,7 @@ import java.nio.charset.StandardCharsets;
*
* @author DB
*/
@Slf4j
public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
@ -26,7 +27,38 @@ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
body = HttpHelper.getBodyString(request).getBytes(StandardCharsets.UTF_8);
body = getBodyString(request).getBytes(StandardCharsets.UTF_8);
}
/**
* 获取主体字符串
*
* @param request 请求
* @return {@link String }
* @author DB
* @since 2024/05/24
*/
private String getBodyString(ServletRequest request) {
StringBuilder sb = new StringBuilder();
BufferedReader reader = null;
try (InputStream inputStream = request.getInputStream()) {
reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
log.warn("getBodyString出现问题");
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
log.error(ExceptionUtils.getMessage(e));
}
}
}
return sb.toString();
}
@Override

View File

@ -1,61 +0,0 @@
package com.cpop.core.filter;
import com.cpop.common.utils.StringUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 防止XSS攻击的过滤器
*
* @author DB
*/
public class XssFilter implements Filter {
/**
* 排除链接
*/
public List<String> excludes = new ArrayList<>();
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String tempExcludes = filterConfig.getInitParameter("excludes");
if (StringUtils.isNotEmpty(tempExcludes)) {
String[] url = tempExcludes.split(",");
for (int i = 0; url != null && i < url.length; i++) {
excludes.add(url[i]);
}
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (handleExcludeURL(req, resp)) {
chain.doFilter(request, response);
return;
}
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(xssRequest, response);
}
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
String url = request.getServletPath();
String method = request.getMethod();
// GET DELETE 不过滤
if (method == null || method.matches("GET") || method.matches("DELETE")) {
return true;
}
return StringUtils.matches(url, excludes);
}
@Override
public void destroy() {
}
}

View File

@ -1,97 +0,0 @@
package com.cpop.core.filter;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.html.EscapeUtil;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* XSS过滤处理
*
* @author DB
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
/**
* @param request
*/
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if (values != null) {
int length = values.length;
String[] escapseValues = new String[length];
for (int i = 0; i < length; i++) {
// 防xss攻击和过滤前后空格
escapseValues[i] = EscapeUtil.clean(values[i]).trim();
}
return escapseValues;
}
return super.getParameterValues(name);
}
@Override
public ServletInputStream getInputStream() throws IOException {
// 非json类型直接返回
if (!isJsonRequest()) {
return super.getInputStream();
}
// 为空直接返回
String json = IOUtils.toString(super.getInputStream(), StandardCharsets.UTF_8);
if (StringUtils.isEmpty(json)) {
return super.getInputStream();
}
// xss过滤
json = EscapeUtil.clean(json).trim();
byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8);
final ByteArrayInputStream bis = new ByteArrayInputStream(jsonBytes);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return true;
}
@Override
public boolean isReady() {
return true;
}
@Override
public int available() throws IOException {
return jsonBytes.length;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return bis.read();
}
};
}
/**
* 是否是Json请求
*/
public boolean isJsonRequest() {
String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
}
}

View File

@ -1,86 +0,0 @@
package com.cpop.core.gateway.miniProgram;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.enums.UserType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
/**
* @author DB
* @Description: 小程序认证过滤器
* @create 2023-08-23 21:03
*/
public class MiniProgramAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public MiniProgramAuthenticationFilter() {
super(new AntPathRequestMatcher("/miniLogin", "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (!"POST".equals(request.getMethod())) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
ObjectMapper mapper = new ObjectMapper();
InputStream inputStream;
Map authenticationBean;
try {
inputStream = request.getInputStream();
authenticationBean = mapper.readValue(inputStream, Map.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
String principal = (String) authenticationBean.get("phone");
if (StringUtils.isBlank(principal)){
throw new AuthenticationServiceException("登录手机号为空");
}
String openId = (String) authenticationBean.get("openId");
if (StringUtils.isBlank(openId)){
throw new AuthenticationServiceException("登录openId为空");
}
String appId = (String) authenticationBean.get("appId");
if (StringUtils.isBlank(appId)){
throw new AuthenticationServiceException("登录appId为空");
}
String brandId = (String) authenticationBean.get("brandId");
if (StringUtils.isBlank(brandId)){
throw new AuthenticationServiceException("登录brandId为空");
}
String nickName = (String) authenticationBean.get("nickName");
String avatar = (String) authenticationBean.get("avatar");
String sourceType = (String) authenticationBean.get("sourceType");
if (StringUtils.isBlank(sourceType)){
throw new AuthenticationServiceException("登录sourceType为空");
}
UserType userType = UserType.valueOf(authenticationBean.get("userType").toString());//传递信息
HashMap<String, Object> credentials = new HashMap<>(2);
credentials.put("appId", appId);
credentials.put("openId", openId);
credentials.put("userType", userType);
credentials.put("brandId", brandId);
credentials.put("nickName", nickName);
credentials.put("avatar", avatar);
credentials.put("sourceType", sourceType);
principal = principal.trim();
MiniProgramAuthenticationToken authRequest = new MiniProgramAuthenticationToken(principal, credentials);
this.setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
protected void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
}

View File

@ -1,40 +0,0 @@
package com.cpop.core.gateway.miniProgram;
import com.cpop.core.base.entity.LoginUser;
import com.cpop.core.base.enums.UserType;
import com.cpop.core.service.CoreService;
import com.cpop.core.utils.SpringUtils;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import java.util.Map;
/**
* @author DB
* @Description: 自定义校验过程
* @create 2023-08-23 21:13
*/
public class MiniProgramAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 这个获取表单输入中返回的用户名;
String phone =(String) authentication.getPrincipal();
// 这个是表单中输入的密码
Map<String,Object> credentials = (Map<String, Object>) authentication.getCredentials();
UserType userType = (UserType) credentials.get("userType");
LoginUser loginUser = SpringUtils.getBean(CoreService.class).loadUserByPhone(phone, userType, credentials);
loginUser.setUserType(UserType.MINI_USER);
MiniProgramAuthenticationToken result = new MiniProgramAuthenticationToken(phone, loginUser);
result.setDetails(loginUser);
return result;
}
@Override
public boolean supports(Class<?> authentication) {
//providerManager会遍历所有;securityConfig中注册的provider集合;根据此方法返回true或false来决定由哪个provider;去校验请求过来的authentication
return (MiniProgramAuthenticationToken.class.isAssignableFrom(authentication));
}
}

View File

@ -1,72 +0,0 @@
package com.cpop.core.gateway.miniProgram;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
/**
* @author DB
* @Description:
* @create 2023-08-23 21:11
*/
public class MiniProgramAuthenticationToken extends AbstractAuthenticationToken {
private final Object principal;
private Object credentials;
/**
* This constructor can be safely used by any code that wishes to create a
* <code>UsernamePasswordAuthenticationToken</code>, as the {@link #isAuthenticated()}
* will return <code>false</code>.
*
*/
public MiniProgramAuthenticationToken(Object principal, Object credentials) {
super(null);
this.principal = principal;
this.credentials = credentials;
setAuthenticated(false);
}
/**
* This constructor should only be used by <code>AuthenticationManager</code> or
* <code>AuthenticationProvider</code> implementations that are satisfied with
* producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
* authentication token.
*
* @param principal
* @param credentials
* @param authorities
*/
public MiniProgramAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
// must use super, as we override
super.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return this.credentials;
}
@Override
public Object getPrincipal() {
return this.principal;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
if (isAuthenticated) {
throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
}
super.setAuthenticated(false);
}
@Override
public void eraseCredentials() {
super.eraseCredentials();
credentials = null;
}
}

View File

@ -1,63 +0,0 @@
package com.cpop.core.gateway.sys;
import com.cpop.core.base.enums.UserType;
import com.cpop.core.gateway.miniProgram.MiniProgramAuthenticationToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
/**
* @author DB
* @createTime 2023/10/19 9:27
* @description
*/
public class SysAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public SysAuthenticationFilter() {
super(new AntPathRequestMatcher("/login", "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
if (!"POST".equals(request.getMethod())) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
//读取表单
ObjectMapper mapper = new ObjectMapper();
InputStream inputStream;
Map authenticationBean;
try {
inputStream = request.getInputStream();
authenticationBean = mapper.readValue(inputStream, Map.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
String principal = (String) authenticationBean.get("username");
String password = (String) authenticationBean.get("password");
UserType userType = UserType.valueOf(authenticationBean.get("userType").toString());
principal = principal.trim();
//传递信息
HashMap<String, Object> credentials = new HashMap<>(2);
credentials.put("password", password);
credentials.put("userType", userType);
SysAuthenticationToken authRequest = new SysAuthenticationToken(principal, credentials);
this.setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
protected void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
}

View File

@ -1,49 +0,0 @@
package com.cpop.core.gateway.sys;
import com.cpop.core.base.entity.LoginUser;
import com.cpop.core.base.enums.UserType;
import com.cpop.core.base.exception.CpopAuthenticationException;
import com.cpop.core.gateway.miniProgram.MiniProgramAuthenticationToken;
import com.cpop.core.service.CoreService;
import com.cpop.core.utils.PasswordEncoder;
import com.cpop.core.utils.SpringUtils;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Map;
/**
* @author DB
* @createTime 2023/10/19 9:36
* @description
*/
public class SysAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 这个获取表单输入中返回的用户名;
String principal = (String) authentication.getPrincipal();
// 这个是表单中输入的密码与用户类型
Map<String, Object> credentials = (Map<String, Object>) authentication.getCredentials();
UserType userType = (UserType) credentials.get("userType");
//认证用户名密码
LoginUser loginUser = SpringUtils.getBean(CoreService.class).loadUserByUsername(principal, userType);
//账号密码校验
boolean password = SpringUtils.getBean(PasswordEncoder.class).matches((String) credentials.get("password"), loginUser.getUser().getPassword());
if (!password){
throw new BadCredentialsException("用户名密码错误!");
}
SysAuthenticationToken result = new SysAuthenticationToken(principal, loginUser);
result.setDetails(loginUser);
return result;
}
@Override
public boolean supports(Class<?> authentication) {
//providerManager会遍历所有;securityConfig中注册的provider集合;根据此方法返回true或false来决定由哪个provider;去校验请求过来的authentication
return (SysAuthenticationToken.class.isAssignableFrom(authentication));
}
}

View File

@ -1,72 +0,0 @@
package com.cpop.core.gateway.sys;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
/**
* @author DB
* @createTime 2023/10/19 9:35
* @description
*/
public class SysAuthenticationToken extends AbstractAuthenticationToken {
private final Object principal;
private Object credentials;
/**
* This constructor can be safely used by any code that wishes to create a
* <code>UsernamePasswordAuthenticationToken</code>, as the {@link #isAuthenticated()}
* will return <code>false</code>.
*
*/
public SysAuthenticationToken(Object principal, Object credentials) {
super(null);
this.principal = principal;
this.credentials = credentials;
setAuthenticated(false);
}
/**
* This constructor should only be used by <code>AuthenticationManager</code> or
* <code>AuthenticationProvider</code> implementations that are satisfied with
* producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
* authentication token.
*
* @param principal 第一个参数
* @param credentials 第二个参数
* @param authorities 认证
*/
public SysAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
// must use super, as we override
super.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return this.credentials;
}
@Override
public Object getPrincipal() {
return this.principal;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
if (isAuthenticated) {
throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
}
super.setAuthenticated(false);
}
@Override
public void eraseCredentials() {
super.eraseCredentials();
credentials = null;
}
}

View File

@ -1,23 +1,17 @@
package com.cpop.core.handler;
import com.cpop.core.base.R;
import cn.dev33.satoken.exception.SaTokenException;
import com.cpop.core.base.entity.R;
import com.cpop.core.base.enums.ErrorCodeEnum;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.common.enums.ErrorCodeEnum;
import io.jsonwebtoken.JwtException;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
/**
@ -29,23 +23,23 @@ import java.util.Objects;
public class GlobalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 无登录异常
*/
@ExceptionHandler(SaTokenException.class)
public R<Void> handleNotLoginException(SaTokenException e) {
log.error(e.getMessage(), e);
return R.fail(e.getCode(), e.getMessage());
}
/**
* 业务异常
*/
@ExceptionHandler(ServiceException.class)
public R handleServiceException(ServiceException e) {
public R<Void> handleServiceException(ServiceException e) {
log.error(e.getMessage(), e);
Integer code = e.getCode();
return null != code ? R.fail(code, e.getMessage()) : R.fail(e.getMessage());
}
/**
* 权限不足
* @param e 权限不足异常
*/
@ExceptionHandler(AccessDeniedException.class)
public R handleException(AccessDeniedException e) {
return R.fail(ErrorCodeEnum.HTTP_401.getInfo());
return R.fail(e.getMessage());
}
/**
@ -55,45 +49,43 @@ public class GlobalExceptionHandler {
* @return
*/
@ExceptionHandler(RuntimeException.class)
public R handleRuntimeException(RuntimeException e, HttpServletRequest request) {
public R<Void> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
String requestUrl = request.getRequestURI();
log.error("请求地址'{}',发生未知异常.", requestUrl, e);
return R.fail(e.getMessage());
}
/**
* 自定义验证异常
* 系统异常
* @param e
* @param request
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error(e.getMessage(), e);
String message = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
return R.fail(message);
@ExceptionHandler(Exception.class)
public R<Void> handleException(Exception e, HttpServletRequest request) {
String requestUrl = request.getRequestURI();
log.error("请求地址'{}',发生系统异常.", requestUrl, e);
return R.fail(e.getMessage());
}
/**
* 自定义验证异常
*/
@ExceptionHandler(BindException.class)
public R handleBindException(BindException e) {
public R<Void> handleBindException(BindException e) {
log.error(e.getMessage(), e);
String message = e.getAllErrors().get(0).getDefaultMessage();
return R.fail(message);
}
/**
* 系统异常
* @author DB
* @since 2023/12/04
* @param e 异常
* @param request 请求
* @return R
* 自定义验证异常
*/
@ExceptionHandler(Exception.class)
public R handleException(Exception e, HttpServletRequest request) {
String requestUrl = request.getRequestURI();
log.error("请求地址'{}',发生系统异常.", requestUrl, e);
return R.fail(e.getMessage());
@ExceptionHandler(MethodArgumentNotValidException.class)
public R<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error(e.getMessage(), e);
String message = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
return R.fail(message);
}
}

View File

@ -1,33 +0,0 @@
package com.cpop.core.handler;
import com.alibaba.fastjson.JSONObject;
import com.cpop.core.base.R;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* @author: DB
* @date: 2022-09-25 16:55
* @Description: 无权限访问处理器
*/
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException {
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
ServletOutputStream outputStream = httpServletResponse.getOutputStream();
R<String> result = R.fail(e.getMessage());
outputStream.write(JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8));
outputStream.flush();
outputStream.close();
}
}

View File

@ -1,33 +0,0 @@
package com.cpop.core.handler;
import com.alibaba.fastjson.JSONObject;
import com.cpop.core.base.R;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* @author: DB
* @date: 2022-09-25 16:40
* @Description: jwt认证失败处理器
*/
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException {
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
ServletOutputStream outputStream = httpServletResponse.getOutputStream();
R<String> result = R.fail("请先登录");
outputStream.write(JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8));
outputStream.flush();
outputStream.close();
}
}

View File

@ -1,77 +0,0 @@
package com.cpop.core.handler;
import com.alibaba.fastjson.JSONObject;
import com.cpop.common.constant.Constants;
import com.cpop.core.base.R;
import com.cpop.core.base.entity.LoginUser;
import com.cpop.core.base.enums.OperationLogEnum;
import com.cpop.core.base.enums.UserType;
import com.cpop.core.service.CoreService;
import com.cpop.core.service.RedisService;
import com.cpop.core.utils.JwtUtils;
import com.cpop.core.utils.MessageUtils;
import com.cpop.core.utils.SpringUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* @author: DB
* @date: 2022-09-25 16:56
* @Description: 登出成功处理器
*/
@Component
public class JwtLogoutSuccessHandler implements LogoutSuccessHandler {
@Autowired
private JwtUtils jwtUtils;
@Autowired
private RedisService redisService;
@Override
public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException {
if (authentication != null) {
new SecurityContextLogoutHandler().logout(httpServletRequest, httpServletResponse, authentication);
}
String jwt = httpServletRequest.getHeader(jwtUtils.getHeader());
//添加退出登录成功日志
Jws<Claims> jws = jwtUtils.getClaimsByToken(jwt);
Claims claim = jws.getBody();
if (claim == null) {
throw new JwtException("token 异常");
}
if (jwtUtils.isTokenExpired(claim)) {
throw new JwtException("token 已过期");
}
String identification = claim.getSubject();
UserType userType = UserType.valueOf(jws.getHeader().get(Constants.USER_TYPE).toString());
//从缓存中获取
JSONObject jsonObject = redisService.getCacheObject(userType.getKey() + identification);
if (null != jsonObject) {
LoginUser loginUser = jsonObject.toJavaObject(LoginUser.class);
SpringUtils.getBean(CoreService.class).insertOperationLog(Constants.SUCCESS, OperationLogEnum.SYSTEM_LOGOUT, loginUser, MessageUtils.message("i18n_operationLog_systemLogout"));
}
//清除缓存
redisService.deleteObject(userType.getKey() + identification);
httpServletResponse.setContentType("application/json;charset=UTF-8");
ServletOutputStream outputStream = httpServletResponse.getOutputStream();
String header = jwtUtils.getHeader();
httpServletResponse.setHeader(header, "");
R<String> result = R.ok(MessageUtils.message("i18n_loginOut_success"));
outputStream.write(JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8));
outputStream.flush();
outputStream.close();
}
}

Some files were not shown because too many files have changed in this diff Show More