feat(open-api): 重构开放接口签名验证逻辑
- 新增 SignInterceptor 用于签名验证 - 添加 BodyWrapperFilter 用于获取请求体 - 重构 SecurityUnitUseStatisticsDTO 数据结构 - 更新 OpenController 接口 - 修改 FastJson2Config 支持表单数据
This commit is contained in:
parent
47cd8d9963
commit
56b0a9dca4
|
@ -2,10 +2,13 @@ package com.changhu.config;
|
||||||
|
|
||||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import com.changhu.support.filter.BodyWrapperFilter;
|
||||||
import com.changhu.support.interceptor.JsonBodyInterceptor;
|
import com.changhu.support.interceptor.JsonBodyInterceptor;
|
||||||
import com.changhu.support.interceptor.OpenApiInterceptor;
|
import com.changhu.support.interceptor.SignInterceptor;
|
||||||
import com.changhu.support.interceptor.UserTypeInterceptor;
|
import com.changhu.support.interceptor.UserTypeInterceptor;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
@ -59,10 +62,19 @@ public class WebConfig implements WebMvcConfigurer {
|
||||||
// 注册clientType 拦截器 用于校验当前用户是否匹配操作客户端
|
// 注册clientType 拦截器 用于校验当前用户是否匹配操作客户端
|
||||||
registry.addInterceptor(new UserTypeInterceptor());
|
registry.addInterceptor(new UserTypeInterceptor());
|
||||||
// 注册开放接口 拦截器 用于校验第三方是否携带指定apiKey
|
// 注册开放接口 拦截器 用于校验第三方是否携带指定apiKey
|
||||||
registry.addInterceptor(new OpenApiInterceptor())
|
registry.addInterceptor(new SignInterceptor())
|
||||||
.addPathPatterns("/open/**");
|
.addPathPatterns("/open/**");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FilterRegistrationBean<BodyWrapperFilter> loggingFilter() {
|
||||||
|
FilterRegistrationBean<BodyWrapperFilter> registrationBean = new FilterRegistrationBean<>();
|
||||||
|
registrationBean.setFilter(new BodyWrapperFilter());
|
||||||
|
registrationBean.addUrlPatterns("/open/*"); // 指定过滤的URL模式
|
||||||
|
registrationBean.setOrder(1000);
|
||||||
|
return registrationBean;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
registry.addMapping("/**")
|
registry.addMapping("/**")
|
||||||
|
|
|
@ -68,4 +68,5 @@ public class OpenController {
|
||||||
public List<ServiceProjectSecurityUserRosterDTO> serviceProjectUserRoster(@Schema(description = "服务项目id") Long serviceProjectId) {
|
public List<ServiceProjectSecurityUserRosterDTO> serviceProjectUserRoster(@Schema(description = "服务项目id") Long serviceProjectId) {
|
||||||
return openApiService.serviceProjectUserRoster(serviceProjectId);
|
return openApiService.serviceProjectUserRoster(serviceProjectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ import com.changhu.module.management.pojo.model.LegalPersonInfo;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 20252
|
* @author 20252
|
||||||
* @createTime 2024/11/18 上午10:32
|
* @createTime 2024/11/18 上午10:32
|
||||||
|
@ -14,41 +16,10 @@ import lombok.Data;
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class SecurityUnitUseStatisticsDTO {
|
public class SecurityUnitUseStatisticsDTO {
|
||||||
@Schema(description = "服务项目id")
|
@Schema(description = "事业单位id")
|
||||||
private Long serviceProjectId;
|
private Long enterprisesUnitId;
|
||||||
@Schema(description = "公安单位id")
|
@Schema(description = "事业单位名称")
|
||||||
private Long policeUnitId;
|
private String enterprisesUnitName;
|
||||||
@Schema(description = "公安单位名称")
|
|
||||||
private String policeUnitName;
|
|
||||||
@Schema(description = "保安单位名称")
|
|
||||||
private String securityUnitName;
|
|
||||||
@Schema(description = "服务项目名称")
|
|
||||||
private String serviceProjectName;
|
|
||||||
@Schema(description = "保安服务类别")
|
|
||||||
private ServiceProjectType type;
|
|
||||||
@Schema(description = "二级类型")
|
|
||||||
private ServiceProjectTwoType twoType;
|
|
||||||
@Schema(description = "外包公司名称")
|
|
||||||
private String outsourceName;
|
|
||||||
|
|
||||||
@Schema(description = "保安人员总数")
|
|
||||||
private Integer securityUserTotal;
|
|
||||||
@Schema(description = "持证保安数量")
|
|
||||||
private Integer haveCardSecurityUserCount;
|
|
||||||
|
|
||||||
@Schema(description = "是否备案")
|
|
||||||
private IsOrNot isFiling;
|
|
||||||
@Schema(description = "证件号(保安服务许可证/备案证)")
|
|
||||||
private String idNumber;
|
|
||||||
|
|
||||||
@Schema(description = "保安单位法人信息")
|
|
||||||
private LegalPersonInfo securityUnitLegalPersonInfo;
|
|
||||||
|
|
||||||
@Schema(description = "项目经理")
|
|
||||||
private String serviceProjectManager;
|
|
||||||
@Schema(description = "项目经理联系方式")
|
|
||||||
private String serviceProjectManagerTelephone;
|
|
||||||
|
|
||||||
@Schema(description = "省")
|
@Schema(description = "省")
|
||||||
private String provinceName;
|
private String provinceName;
|
||||||
@Schema(description = "市")
|
@Schema(description = "市")
|
||||||
|
@ -57,5 +28,52 @@ public class SecurityUnitUseStatisticsDTO {
|
||||||
private String districtsName;
|
private String districtsName;
|
||||||
@Schema(description = "街道")
|
@Schema(description = "街道")
|
||||||
private String streetName;
|
private String streetName;
|
||||||
|
@Schema(description = "事业单位详细地址")
|
||||||
|
private String address;
|
||||||
|
@Schema(description = "服务项目列表")
|
||||||
|
List<_ServiceProjectVo> serviceProjectList;
|
||||||
|
|
||||||
|
@Schema(description = "公安单位id")
|
||||||
|
private Long policeUnitId;
|
||||||
|
@Schema(description = "公安单位名称")
|
||||||
|
private String policeUnitName;
|
||||||
|
|
||||||
|
@Schema(description = "保安单位id")
|
||||||
|
private Long securityUnitId;
|
||||||
|
@Schema(description = "保安单位名称")
|
||||||
|
private String securityUnitName;
|
||||||
|
@Schema(description = "保安单位法人信息")
|
||||||
|
private LegalPersonInfo securityUnitLegalPersonInfo;
|
||||||
|
|
||||||
|
@Schema(description = "项目经理")
|
||||||
|
private String serviceProjectManager;
|
||||||
|
@Schema(description = "项目经理联系方式")
|
||||||
|
private String serviceProjectManagerTelephone;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
static class _ServiceProjectVo {
|
||||||
|
@Schema(description = "服务项目id")
|
||||||
|
private Long snowFlakeId;
|
||||||
|
@Schema(description = "服务项目名称")
|
||||||
|
private String name;
|
||||||
|
@Schema(description = "保安服务类别")
|
||||||
|
private ServiceProjectType type;
|
||||||
|
@Schema(description = "二级类型")
|
||||||
|
private ServiceProjectTwoType twoType;
|
||||||
|
|
||||||
|
@Schema(description = "外包公司名称")
|
||||||
|
private String outsourceName;
|
||||||
|
@Schema(description = "是否备案")
|
||||||
|
private IsOrNot isFiling;
|
||||||
|
@Schema(description = "证件号(保安服务许可证/备案证)")
|
||||||
|
private String idNumber;
|
||||||
|
|
||||||
|
@Schema(description = "保安人员总数")
|
||||||
|
private Integer securityUserTotal;
|
||||||
|
@Schema(description = "持证保安数量")
|
||||||
|
private Integer haveCardSecurityUserCount;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,8 @@ public class FastJson2Config {
|
||||||
|
|
||||||
//4.解决中文乱码问题,相当于在Controller上的@RequestMapping中加了个属性produces = "application/json"
|
//4.解决中文乱码问题,相当于在Controller上的@RequestMapping中加了个属性produces = "application/json"
|
||||||
fastConverter.setSupportedMediaTypes(List.of(
|
fastConverter.setSupportedMediaTypes(List.of(
|
||||||
MediaType.APPLICATION_JSON
|
MediaType.APPLICATION_JSON,
|
||||||
|
MediaType.APPLICATION_FORM_URLENCODED
|
||||||
));
|
));
|
||||||
return fastConverter;
|
return fastConverter;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.changhu.support.filter;
|
||||||
|
|
||||||
|
import jakarta.servlet.*;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 20252
|
||||||
|
* @createTime 2024/11/19 下午3:07
|
||||||
|
* @desc BodyWrapperFilter...
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class BodyWrapperFilter implements Filter {
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||||
|
log.info("进入filter:{}", servletRequest.getRemoteAddr());
|
||||||
|
ServletRequest requestWrapper = null;
|
||||||
|
if (servletRequest instanceof HttpServletRequest) {
|
||||||
|
requestWrapper = new CustomHttpServletRequestWrapper((HttpServletRequest) servletRequest);
|
||||||
|
}
|
||||||
|
filterChain.doFilter(Objects.requireNonNullElse(requestWrapper, servletRequest), servletResponse);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package com.changhu.support.filter;
|
||||||
|
|
||||||
|
import jakarta.servlet.ReadListener;
|
||||||
|
import jakarta.servlet.ServletInputStream;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 20252
|
||||||
|
* @createTime 2024/11/19 下午3:12
|
||||||
|
* @desc CustomHttpServletRequestWrapper...
|
||||||
|
*/
|
||||||
|
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
||||||
|
private final byte[] body;
|
||||||
|
|
||||||
|
public CustomHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
|
||||||
|
super(request);
|
||||||
|
BufferedReader reader = request.getReader();
|
||||||
|
try (StringWriter writer = new StringWriter()) {
|
||||||
|
int read;
|
||||||
|
char[] buf = new char[1024 * 8];
|
||||||
|
while ((read = reader.read(buf)) != -1) {
|
||||||
|
writer.write(buf, 0, read);
|
||||||
|
}
|
||||||
|
this.body = writer.getBuffer().toString().getBytes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBody() {
|
||||||
|
return new String(body, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServletInputStream getInputStream() {
|
||||||
|
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
|
||||||
|
return new ServletInputStream() {
|
||||||
|
@Override
|
||||||
|
public boolean isFinished() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReady() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReadListener(ReadListener readListener) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() {
|
||||||
|
return byteArrayInputStream.read();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BufferedReader getReader() {
|
||||||
|
return new BufferedReader(new InputStreamReader(this.getInputStream()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
package com.changhu.support.interceptor;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.core.util.URLUtil;
|
||||||
|
import cn.hutool.crypto.digest.MD5;
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
|
import com.alibaba.fastjson2.TypeReference;
|
||||||
|
import com.baomidou.mybatisplus.extension.toolkit.Db;
|
||||||
|
import com.changhu.common.db.enums.IsEnable;
|
||||||
|
import com.changhu.common.exception.MessageException;
|
||||||
|
import com.changhu.common.utils.IpUtil;
|
||||||
|
import com.changhu.pojo.entity.AccessKeys;
|
||||||
|
import com.changhu.support.filter.CustomHttpServletRequestWrapper;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.web.method.HandlerMethod;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 20252
|
||||||
|
* @createTime 2024/11/19 下午1:58
|
||||||
|
* @desc SignInterceptor...
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class SignInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
private static final String ACCESS_KEY = "Access-Key";//调用者身份唯一标识
|
||||||
|
private static final String TIMESTAMP = "Time-Stamp";//时间戳
|
||||||
|
private static final String SIGN = "Sign";//签名
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(@NotNull HttpServletRequest request,
|
||||||
|
@NotNull HttpServletResponse response,
|
||||||
|
@NotNull Object handler) throws Exception {
|
||||||
|
if (handler instanceof HandlerMethod) {
|
||||||
|
String ip = IpUtil.getIp(request);
|
||||||
|
try {
|
||||||
|
return checkSign(request);
|
||||||
|
} catch (MessageException e) {
|
||||||
|
log.error("开放接口访问失败:{} 访问时间:{} IP:{} 访问接口:{} ", e.getMessage(), LocalDateTime.now(), ip, request.getRequestURI());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkSign(HttpServletRequest request) throws MessageException {
|
||||||
|
|
||||||
|
String accessKey = request.getHeader(ACCESS_KEY);
|
||||||
|
String timestamp = request.getHeader(TIMESTAMP);
|
||||||
|
String sign = request.getHeader(SIGN);
|
||||||
|
|
||||||
|
if (StrUtil.isBlank(accessKey) || StrUtil.isBlank(timestamp) || StrUtil.isBlank(sign)) {
|
||||||
|
throw new MessageException("请求体缺失");
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessKeys accessKeyEntity = Db.lambdaQuery(AccessKeys.class)
|
||||||
|
.eq(AccessKeys::getAccessKey, accessKey)
|
||||||
|
.oneOpt()
|
||||||
|
.orElseThrow(() -> new MessageException("无效的accessKey"));
|
||||||
|
|
||||||
|
if (IsEnable.FALSE.equals(accessKeyEntity.getIsEnable())) {
|
||||||
|
throw new MessageException("无效的accessKey");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessKeyEntity.getEffectiveTime() > 0 && System.currentTimeMillis() - Long.parseLong(timestamp) > accessKeyEntity.getEffectiveTime()) {
|
||||||
|
throw new MessageException("请求已过期");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> allowedResources = Optional.ofNullable(accessKeyEntity.getAllowedResources()).orElseThrow(() -> new MessageException("暂无允许访问的资源"));
|
||||||
|
if (!allowedResources.contains(request.getRequestURI())) {
|
||||||
|
throw new MessageException("无效的请求资源");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> hashMap = new HashMap<>();
|
||||||
|
//添加请求url参数
|
||||||
|
Map<String, String> map = HttpUtil.decodeParamMap(request.getQueryString(), StandardCharsets.UTF_8);
|
||||||
|
if (!map.isEmpty()) {
|
||||||
|
hashMap.putAll(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
hashMap.put(ACCESS_KEY, accessKey);
|
||||||
|
hashMap.put(TIMESTAMP, timestamp);
|
||||||
|
//添加body参数
|
||||||
|
CustomHttpServletRequestWrapper c = (CustomHttpServletRequestWrapper) request;
|
||||||
|
Optional.ofNullable(new TypeReference<Map<String, Object>>() {
|
||||||
|
}.parseObject(c.getBody())).ifPresent(hashMap::putAll);
|
||||||
|
|
||||||
|
String nowSign = generatedSign(hashMap, accessKeyEntity.getSecretKey());
|
||||||
|
if (!sign.equals(nowSign)) {
|
||||||
|
throw new MessageException("签名错误");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取签名
|
||||||
|
*
|
||||||
|
* @param map 参数结果
|
||||||
|
* @param secretKey 密钥
|
||||||
|
* @return 签名字符串
|
||||||
|
*/
|
||||||
|
private String generatedSign(Map<String, Object> map, String secretKey) {
|
||||||
|
List<Map.Entry<String, Object>> entries = new ArrayList<>(map.entrySet());
|
||||||
|
String str = entries.stream()
|
||||||
|
.filter(en -> null == en.getValue() || StrUtil.isNotBlank(en.getValue().toString()))
|
||||||
|
.sorted(Comparator.comparing(o -> o.getKey().toLowerCase()))
|
||||||
|
.map(en -> StrUtil.format("{}={}", en.getKey(), URLUtil.encodeAll(en.getValue() + "")))
|
||||||
|
.collect(Collectors.joining("&"));
|
||||||
|
str += ("&Secret-Key=" + secretKey);
|
||||||
|
return MD5.create().digestHex(str).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
String str1 = "Access-Key=w2wzi0wefmmo6s735z2el8tfzitya5gj&addr=%E6%B9%96%E5%8D%97%E7%9C%81%E9%95%BF%E6%B2%99%E5%B8%82&age=14&name=zhangsan&Time-Stamp=1732084303463&Secret-Key=db1b5214-02ee-497f-957c-88323b4351bf";
|
||||||
|
String str2 = "Access-Key=w2wzi0wefmmo6s735z2el8tfzitya5gj&addr=%E6%B9%96%E5%8D%97%E7%9C%81%E9%95%BF%E6%B2%99%E5%B8%82&age=14&name=zhangsan&Time-Stamp=1732084303463&Secret-Key=db1b5214-02ee-497f-957c-88323b4351bf";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -33,40 +33,61 @@
|
||||||
column="securityUnitLegalPersonInfo"
|
column="securityUnitLegalPersonInfo"
|
||||||
typeHandler="com.baomidou.mybatisplus.extension.handlers.Fastjson2TypeHandler"
|
typeHandler="com.baomidou.mybatisplus.extension.handlers.Fastjson2TypeHandler"
|
||||||
property="securityUnitLegalPersonInfo"/>
|
property="securityUnitLegalPersonInfo"/>
|
||||||
|
<result
|
||||||
|
column="serviceProjectList"
|
||||||
|
typeHandler="com.baomidou.mybatisplus.extension.handlers.Fastjson2TypeHandler"
|
||||||
|
property="serviceProjectList"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<select id="securityUnitUseStatistics" resultMap="SecurityUnitUseStatisticsDTOResultMap">
|
<select id="securityUnitUseStatistics" resultMap="SecurityUnitUseStatisticsDTOResultMap">
|
||||||
|
WITH security_user_counts AS (
|
||||||
|
SELECT
|
||||||
|
service_project_id,
|
||||||
|
COUNT(1) AS securityUserTotal,
|
||||||
|
SUM(IF(security_number != '', 1, 0)) AS haveCardSecurityUserCount
|
||||||
|
FROM
|
||||||
|
security_user
|
||||||
|
WHERE delete_flag = 0
|
||||||
|
GROUP BY service_project_id )
|
||||||
select
|
select
|
||||||
sp.snow_flake_id as 'serviceProjectId',
|
eu.snow_flake_id as 'enterprisesUnitId',
|
||||||
pu.snow_flake_id as 'policeUnitId',
|
eu.name as 'enterprisesUnitName',
|
||||||
pu.name as 'policeUnitName',
|
|
||||||
su.name as 'securityUnitName',
|
|
||||||
sp.name as 'serviceProjectName',
|
|
||||||
sp.type as 'type',
|
|
||||||
sp.two_type as 'twoType',
|
|
||||||
sp.outsource_name as 'outsourceName',
|
|
||||||
count(suu.snow_flake_id) as 'securityUserTotal',
|
|
||||||
SUM(IF(suu.security_number != '', 1, 0)) as 'haveCardSecurityUserCount',
|
|
||||||
sp.is_filing as 'isFiling',
|
|
||||||
sp.id_number,
|
|
||||||
su.legal_person_info as 'securityUnitLegalPersonInfo',
|
|
||||||
mpu.name as 'serviceProjectManagerName',
|
|
||||||
mpu.telephone as 'serviceProjectManagerTelephone',
|
|
||||||
ad1.name as 'provinceName',
|
ad1.name as 'provinceName',
|
||||||
ad2.name as 'cityName',
|
ad2.name as 'cityName',
|
||||||
ad3.name as 'districtsName',
|
ad3.name as 'districtsName',
|
||||||
ad4.name as 'streetName'
|
ad4.name as 'streetName',
|
||||||
from police_unit pu
|
eu.address as 'address',
|
||||||
|
pu.snow_flake_id as 'policeUnitId',
|
||||||
|
pu.name as 'policeUnitName',
|
||||||
|
su.snow_flake_id as 'securityUnitId',
|
||||||
|
su.name as 'securityUnitName',
|
||||||
|
su.legal_person_info as 'securityUnitLegalPersonInfo',
|
||||||
|
mpu.name as 'serviceProjectManagerName',
|
||||||
|
mpu.telephone as 'serviceProjectManagerTelephone',
|
||||||
|
json_arrayagg(
|
||||||
|
json_object(
|
||||||
|
'snowFlakeId', sp.snow_flake_id,
|
||||||
|
'name', sp.name,
|
||||||
|
'type', sp.type,
|
||||||
|
'twoType', sp.two_type,
|
||||||
|
'outsourceName', sp.outsource_name,
|
||||||
|
'isFiling', sp.is_filing,
|
||||||
|
'idNumber', sp.id_number,
|
||||||
|
'securityUserTotal', suc.securityUserTotal,
|
||||||
|
'haveCardSecurityUserCount', suc.haveCardSecurityUserCount
|
||||||
|
)) as 'serviceProjectList'
|
||||||
|
from
|
||||||
|
police_unit pu
|
||||||
join enterprises_unit eu on pu.snow_flake_id = eu.police_unit_id and eu.delete_flag = 0
|
join enterprises_unit eu on pu.snow_flake_id = eu.police_unit_id and eu.delete_flag = 0
|
||||||
join service_project sp on eu.snow_flake_id = sp.enterprises_unit_id and sp.delete_flag = 0
|
join service_project sp on eu.snow_flake_id = sp.enterprises_unit_id and sp.delete_flag = 0
|
||||||
join security_unit su on sp.security_unit_id = su.snow_flake_id and su.delete_flag = 0
|
join security_unit su on sp.security_unit_id = su.snow_flake_id and su.delete_flag = 0
|
||||||
LEFT join mini_program_user mpu on sp.project_manager_mini_program_user_id = mpu.snow_flake_id
|
LEFT join mini_program_user mpu on sp.project_manager_mini_program_user_id = mpu.snow_flake_id
|
||||||
LEFT join security_user suu on suu.service_project_id = sp.snow_flake_id and suu.delete_flag = 0
|
|
||||||
left join administrative_division ad1 on eu.province = ad1.code and ad1.delete_flag = 0
|
left join administrative_division ad1 on eu.province = ad1.code and ad1.delete_flag = 0
|
||||||
left join administrative_division ad2 on eu.city = ad2.code and ad2.delete_flag = 0
|
left join administrative_division ad2 on eu.city = ad2.code and ad2.delete_flag = 0
|
||||||
left join administrative_division ad3 on eu.districts = ad3.code and ad3.delete_flag = 0
|
left join administrative_division ad3 on eu.districts = ad3.code and ad3.delete_flag = 0
|
||||||
left join administrative_division ad4 on eu.street = ad4.code and ad4.delete_flag = 0
|
left join administrative_division ad4 on eu.street = ad4.code and ad4.delete_flag = 0
|
||||||
|
left JOIN security_user_counts suc ON sp.snow_flake_id = suc.service_project_id
|
||||||
where pu.delete_flag = 0
|
where
|
||||||
|
pu.delete_flag = 0
|
||||||
<choose>
|
<choose>
|
||||||
<when test="level==1">
|
<when test="level==1">
|
||||||
and eu.province = #{code}
|
and eu.province = #{code}
|
||||||
|
@ -85,8 +106,8 @@
|
||||||
</when>
|
</when>
|
||||||
<otherwise>and eu.snow_flake_id = -1</otherwise>
|
<otherwise>and eu.snow_flake_id = -1</otherwise>
|
||||||
</choose>
|
</choose>
|
||||||
group by sp.snow_flake_id
|
group by eu.snow_flake_id
|
||||||
order by sp.create_time desc
|
order by eu.create_time desc
|
||||||
</select>
|
</select>
|
||||||
<select id="serviceProjectUserRoster"
|
<select id="serviceProjectUserRoster"
|
||||||
resultType="com.changhu.pojo.dto.ServiceProjectSecurityUserRosterDTO">
|
resultType="com.changhu.pojo.dto.ServiceProjectSecurityUserRosterDTO">
|
||||||
|
|
Loading…
Reference in New Issue