充电桩协议算法实现

This commit is contained in:
ZZ 2021-07-13 17:50:09 +08:00
parent 1d7815f6bb
commit 72650698cc
32 changed files with 2304 additions and 2 deletions

View File

@ -20,7 +20,7 @@
<spring-boot.version>2.5.1</spring-boot.version>
<spring-cloud.version>2020.0.3</spring-cloud.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
<alibaba.nacos.version>1.1.4</alibaba.nacos.version>
<alibaba.nacos.version>2.0.2</alibaba.nacos.version>
<spring-boot-admin.version>2.4.1</spring-boot-admin.version>
<spring-boot.mybatis>2.1.4</spring-boot.mybatis>
<swagger.fox.version>3.0.0</swagger.fox.version>
@ -246,6 +246,7 @@
<module>ruoyi-modules</module>
<module>ruoyi-api</module>
<module>ruoyi-common</module>
<module>xhpc-modules</module>
</modules>
<packaging>pom</packaging>

View File

@ -0,0 +1,60 @@
package com.ruoyi.common.core.utils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
public class GetIpAndPort {
private static String ip;
//获取ip
public static String getLocalIP() {
if (ip==null) {
String localIP = "127.0.0.1";
try {
OK:
for (Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements(); ) {
NetworkInterface networkInterface = interfaces.nextElement();
if (networkInterface.isLoopback() || networkInterface.isVirtual() || !networkInterface.isUp()) {
continue;
}
Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if (address instanceof Inet4Address) {
localIP = address.getHostAddress();
break OK;
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
ip = localIP;
}
return ip;
}
//通过request获取ip
public static String getIp() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getServerName();
}
//通过request获取端口
public static String getLocalPort() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getServerPort() + "";
}
public static String getIpAndPort() {
return getLocalIP() + "#" + getLocalPort();
}
}

22
xhpc-modules/pom.xml Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<modules>
<module>xhpc-power-pole</module>
</modules>
<artifactId>xhpc-modules</artifactId>
<packaging>pom</packaging>
<description>
充电业务模块
</description>
</project>

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>xhpc-modules</artifactId>
<version>3.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>xhpc-power-pole</artifactId>
<description>
充电桩服务
</description>
<dependencies>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Mysql Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- RuoYi Common DataSource -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-datasource</artifactId>
</dependency>
<!-- RuoYi Common DataScope -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-datascope</artifactId>
</dependency>
<dependency>
<groupId>org.quickserver</groupId>
<artifactId>quickserver</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,29 @@
package com.xhpc.pp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
* 充电桩服务
*
* @author zz
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class XhpcPPApplication
{
public static void main(String[] args) {
SpringApplication.run(XhpcPPApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ 充电桩服务模块启动成功 ლ(´ڡ`ლ)゙ \n" +
" .-------. ____ __ \n" +
" | _ _ \\ \\ \\ / / \n" +
" | ( ' ) | \\ _. / ' \n" +
" |(_ o _) / _( )_ .' \n" +
" | (_,_).' __ ___(_ o _)' \n" +
" | |\\ \\ | || |(_,_)' \n" +
" | | \\ `' /| `-' / \n" +
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
}

View File

@ -0,0 +1,26 @@
package com.xhpc.pp.config;
import com.xhpc.pp.tx.logic.ServiceLogic;
import com.xhpc.pp.utils.SpringContextHolder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class EarlierBeanConf {
final
SpringContextHolder springContextHolder;
public EarlierBeanConf(SpringContextHolder springContextHolder) {
this.springContextHolder = springContextHolder;
}
@Bean
public Map<String, ServiceLogic> serviceLogics() {
return new HashMap<>();
}
}

View File

@ -0,0 +1,29 @@
package com.xhpc.pp.controller;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.ruoyi.common.core.utils.GetIpAndPort;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class TestController {
@GetMapping("test")
public String test() throws NacosException {
String serverIp = "127.0.0.1";
int serverPort = 8848;
String serverAddr = serverIp + ":" + serverPort;
NamingService namingService = NacosFactory.createNamingService(serverAddr);
List<Instance> ppInstances = namingService.getAllInstances("xhpc-power-pole");
String ipAndPort = GetIpAndPort.getIpAndPort();
return ipAndPort;
}
}

View File

@ -0,0 +1,94 @@
package com.xhpc.pp.domain;
public class ServiceField {
private Long id;
private String serviceName;
private String version;
private String name;
private String code;
private Integer len;
private Integer seq;
private String remark;
private String dataType;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Integer getLen() {
return len;
}
public void setLen(Integer len) {
this.len = len;
}
public Integer getSeq() {
return seq;
}
public void setSeq(Integer seq) {
this.seq = seq;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
}

View File

@ -0,0 +1,23 @@
package com.xhpc.pp.mapper;
import com.xhpc.pp.domain.ServiceField;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;
@Mapper
public interface ServiceFieldMapper {
int deleteByPrimaryKey(Long id);
int insert(ServiceField record);
ServiceField selectByPrimaryKey(Long id);
List<ServiceField> query(Map<String, Object> query);
int updateByPrimaryKey(ServiceField record);
List<Map<String, Object>> querySQL(Map<String, String> query);
}

View File

@ -0,0 +1,169 @@
package com.xhpc.pp.server;
import com.xhpc.pp.domain.ServiceField;
import com.xhpc.pp.service.FieldService;
import com.xhpc.pp.service.ServiceMainLogic;
import com.xhpc.pp.tx.ServiceParameter;
import com.xhpc.pp.tx.ServiceResult;
import com.xhpc.pp.tx.TxException;
import com.xhpc.pp.utils.SpringContextHolder;
import com.xhpc.pp.utils.security.CRCCalculator;
import com.xhpc.pp.utils.security.HexUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.quickserver.net.server.ClientBinaryHandler;
import org.quickserver.net.server.ClientHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.*;
public class PPPBinaryHandler implements ClientBinaryHandler {
private static final Logger log = LoggerFactory.getLogger(PPPBinaryHandler.class);
private static final String SERVICE_REGISTER = "1001";
private static final String SERVICE_LOGOUT = "1002";
private static final String DATA_TYPE_STRING = "string";
private static final String DATA_TYPE_INT = "int";
private static final String DATA_TYPE_LONG = "long";
// private static final String DATA_TYPE_HEX = "hex";
private ServiceMainLogic servicemainLogic;
public PPPBinaryHandler() {
servicemainLogic = SpringContextHolder.getBean("ServiceMainLogic");
}
@Override
public void handleBinary(ClientHandler handler, byte[] data) throws IOException {
String dataStr = HexUtils.toHex(data);
String poleNo = PPPServer.getPoleNo(handler);
if (poleNo==null) {
log.info("received message <<<< {}, len[{}]", dataStr, data.length);
} else if (!dataStr.startsWith("00101005000100040000000000000000")) {
log.info("received pole [{}] message <<<< {}, len[{}]", poleNo, dataStr, data.length);
}
try {
// CRC校验和
byte[] data2 = Arrays.copyOfRange(data, 2, data.length-2);
String crc1 = CRCCalculator.ModbusCRC(data2, data2.length);
// 检验长度
if (data.length <= 2) {
log.error("input data invalid. " + data);
return;
}
int len = HexUtils.toInteger(data, 1, 2);
if (data.length < len) {
log.error("input data length. " + data.length);
return;
}
// 处理粘包
List<byte[]> dataList = parseDataList(data);
for (byte[] d : dataList) {
process(handler, d);
}
} catch (TxException e) {
log.error(e.getMessage(), e);
}
}
//
private void process(ClientHandler handler, byte[] data) throws TxException, IOException {
String serviceName = HexUtils.toHex(data, 5, 6);
String version = PPPServer.getVersion(handler.getName());
String poleNo = PPPServer.getPoleNo(handler);
Map<String, Object> req = analysis(data, serviceName, version);
// log.info("pole [{}] status: |{}|", StringUtils.isNotBlank(poleNo) ? poleNo : "null", req.get("status") != null ? MQPole.PoleStatus.toString((Long) req.get("status")) : "N/A");
ServiceParameter sp = new ServiceParameter(serviceName, poleNo, req);
// try {
// log.info("serviceLogic: |{}|", servicemainLogic.getServiceLogic(serviceName).getClass().getName());
// } catch (Exception e) {
// e.printStackTrace();
// }
//service 主逻辑中解析参数为对应的服务
ServiceResult result = servicemainLogic.process(sp);
// 结果不为空的直接回写
if (result.getBinary() != null) {
log.info("server send msg >>>> [{}] |{}|", poleNo, HexUtils.toHex(result.getBinary()));
handler.sendClientBinary(result.getBinary());
}
// 注册成功后需要将当前handler与设备关联
if (SERVICE_REGISTER.equals(serviceName)) {
PPPServer.putHandler((String) req.get("poleNo"), handler);
PPPServer.putVersion(handler.getName(), (String) req.get("version"));
}
// 注销后将桩号对应关系解除
if (SERVICE_LOGOUT.equals(serviceName)) {
PPPServer.removeHandler(poleNo);
}
}
private List<byte[]> parseDataList(byte[] data) {
List<byte[]> dataList = new ArrayList<>();
int len = HexUtils.toInteger(data, 1, 2);
int start = 0;
while (start < data.length) {
if (len > data.length) {
log.error("input data[{}] len[{}]", data, data.length);
break;
}
dataList.add(ArrayUtils.subarray(data, start, len));
start = len;
len = len + HexUtils.toInteger(data, start, start + 2);
}
if (dataList.size() > 1) {
log.info("detection stick package size[{}]", dataList.size());
}
return dataList;
}
private Map<String, Object> analysis(byte[] data, String service, String ver) throws TxException {
List<ServiceField> fieldList = FieldService.fieldList(ver, service);
if (fieldList == null || fieldList.isEmpty())
throw TxException.INNER_ERROR("field mapper not found");
Map<String, Object> result = new HashMap<String, Object>();
int pos = 4;
// TODO 终止充电详情原因
for (ServiceField field : fieldList) {
// 判断长度 某些报文不同版本长度不同
if (pos >= data.length || pos + field.getLen() > data.length)
break;
switch (field.getDataType()) {
case DATA_TYPE_STRING:
result.put(field.getCode(), HexUtils.toString(data, pos, pos + field.getLen()));
break;
case DATA_TYPE_INT:
result.put(field.getCode(), HexUtils.byte2int(ArrayUtils.subarray(data, pos, pos + field.getLen())));
break;
case DATA_TYPE_LONG:
result.put(field.getCode(), HexUtils.byte2Long(ArrayUtils.subarray(data, pos, pos + field.getLen())));
break;
default:
result.put(field.getCode(), HexUtils.toHex(data, pos, pos + field.getLen()));
}
pos += field.getLen();
}
// 原始报文
result.put("hex", HexUtils.toHex(data));
return result;
}
}

View File

@ -0,0 +1,26 @@
package com.xhpc.pp.server;
import org.quickserver.net.server.ClientCommandHandler;
import org.quickserver.net.server.ClientHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import java.io.IOException;
import java.net.SocketTimeoutException;
@Repository
public class PPPCommandHandler implements ClientCommandHandler {
private static final Logger log = LoggerFactory.getLogger(PPPCommandHandler.class);
public PPPCommandHandler() {
}
@Override
public void handleCommand(ClientHandler handler, String appData) throws SocketTimeoutException, IOException {
log.info("handleCommand <====" + appData);
}
}

View File

@ -0,0 +1,43 @@
package com.xhpc.pp.server;
import org.quickserver.net.server.ClientEventHandler;
import org.quickserver.net.server.ClientHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.SocketTimeoutException;
@Lazy(false)
@Component
public class PPPEventHandler implements ClientEventHandler {
private static final Logger log = LoggerFactory.getLogger(PPPEventHandler.class);
public PPPEventHandler() {
}
@Override
public void gotConnected(ClientHandler handler) throws SocketTimeoutException, IOException {
log.info("got connected -> " + handler.getName() + " <-" + handler.getSocket().getRemoteSocketAddress().toString());
// TODO 连接时获取终端唯一标示断开连接时根据唯一标示绑定的桩号更新桩状态
// 请求注册
}
@Override
public void lostConnection(ClientHandler handler) {
String poleNo = PPPServer.getPoleNo(handler);
log.info("lost connection -> [{}] {} <- {}",
poleNo, handler.getName(), handler.getSocket().getRemoteSocketAddress().toString());
if (poleNo != null) {
PPPServer.removeHandler(poleNo);
}
}
@Override
public void closingConnection(ClientHandler handler) throws IOException {
log.info("closing connection -> " + handler.getName() + " <-");
}
}

View File

@ -0,0 +1,132 @@
package com.xhpc.pp.server;
import com.xhpc.pp.utils.security.HexUtils;
import org.quickserver.net.server.ClientHandler;
import org.quickserver.net.server.DataMode;
import org.quickserver.net.server.DataType;
import org.quickserver.net.server.QuickServer;
import org.quickserver.util.xmlreader.DefaultDataMode;
import org.quickserver.util.xmlreader.QuickServerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 充电桩服务器
*/
@Lazy(false)
@Component
public class PPPServer {
public static final String default_version = "0A";
private static final Logger log = LoggerFactory.getLogger(PPPServer.class);
private static Map<String, ClientHandler> handlerMapper = new HashMap<>();
private static Map<String, String> versionMapper = new HashMap<>();
private static Map<String, String> poleMapper = new HashMap<>();
private QuickServer server;
@Autowired
public PPPServer(@Value("${ppsvc.server}") String host, @Value("${ppsvc.port}") int port) {
try {
QuickServerConfig config;
server = new QuickServer();
server.setDefaultDataMode(DataMode.BINARY, DataType.IN);
config = new QuickServerConfig();
DefaultDataMode mode = new DefaultDataMode();
mode.setDataMode(DataMode.BINARY, DataType.IN);
mode.setDataMode(DataMode.BINARY, DataType.OUT);
config.setDefaultDataMode(mode);
config.setClientEventHandler(PPPEventHandler.class.getName());
config.setClientCommandHandler(PPPCommandHandler.class.getName());
config.setClientBinaryHandler(PPPBinaryHandler.class.getName());
config.getServerMode().setBlocking(true);
config.setPort(port);
config.setBindAddr(host);
config.setTimeout(60 * 1000 * 5);
server.initService(config);
server.startServer();
log.info("pp svc started at {}:{} ....", host, port);
} catch (Exception e) {
e.printStackTrace();
log.error("pp svc start error: " + e);
}
}
public static void putHandler(String poleNo, ClientHandler handler) {
poleNo = HexUtils.toIntString(poleNo, 4);
handlerMapper.put(poleNo, handler);
poleMapper.put(handler.getName(), poleNo);
}
public static void removeHandler(String poleNo) {
ClientHandler handler = handlerMapper.remove(poleNo);
if (handler != null) {
log.info("remove hanlder [{}], poleNo[{}]", handler.getName(), poleNo);
poleMapper.remove(handler.getName());
versionMapper.remove(handler.getName());
}
}
public static void sendClientMsg(String poleNo, byte[] msg) {
//TODO 采集服务器充电桩 协议0x100A
if (!HexUtils.toHex(msg).startsWith("00101005")) {
log.info("server send msg >>>> [{}] |{}|", poleNo, HexUtils.toHex(msg));
}
if (poleNo.length() < 16) {
poleNo = "0000000000000000" + poleNo;
poleNo = poleNo.substring(poleNo.length() - 16);
}
ClientHandler handler = handlerMapper.get(poleNo);
if (handler == null || !handler.isOpen()) {
log.error("send message failed. [{}] connection lost", poleNo);
removeHandler(poleNo);
return;
}
try {
handler.sendClientBinary(msg);
} catch (IOException e) {
log.error("send message failed. " + e.getMessage(), e);
}
return;
}
public static void putVersion(String handler, String version) {
versionMapper.put(handler, version);
}
public static String getVersion(String handler) {
String version = versionMapper.get(handler);
if (version == null)
version =default_version;
return version;
}
public static ClientHandler getHandler(String poleNo) {
return handlerMapper.get(poleNo);
}
public static String getPoleNo(ClientHandler handler) {
return poleMapper.get(handler.getName());
}
public void shutDown() {
try {
if (server != null)
server.stopServer();
} catch (Exception e) {
log.error("Server could not stop: " + e);
}
}
}

View File

@ -0,0 +1,74 @@
package com.xhpc.pp.service;
import com.xhpc.pp.domain.ServiceField;
import com.xhpc.pp.mapper.ServiceFieldMapper;
import com.xhpc.pp.server.PPPServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Lazy
@Component
public class FieldService {
// 版本->协议字段表
private static Map<String, Map<String, List<ServiceField>>> versionMapFields;
private static ServiceFieldMapper fieldMapper;
@Autowired
public FieldService(ServiceFieldMapper fieldMapper) {
FieldService.fieldMapper = fieldMapper;
FieldService.refreshCache();
}
public static void refreshCache() {
versionMapFields.clear();
init();
}
public static void init() {
versionMapFields = new HashMap<>();
List<ServiceField> list = fieldMapper.query(null);
for (ServiceField field : list) {
String version = field.getVersion();
String service = field.getServiceName();
Map<String, List<ServiceField>> versionMap = versionMapFields.computeIfAbsent(version, k -> new HashMap<>());
List<ServiceField> fields = versionMap.computeIfAbsent(service, k -> new ArrayList<>());
fields.add(field);
}
}
public static List<ServiceField> fieldList(String version, String service) {
Map<String, List<ServiceField>> vermap = versionMapFields.get(version);
// 充电桩上送的版本未维护使用默认版本
if (vermap == null)
vermap = versionMapFields.get(PPPServer.default_version);
if (vermap == null)
return null;
// 上送的版本当前接口未维护使用默认版本
List<ServiceField> fieldList = vermap.get(service);
if (fieldList == null || fieldList.isEmpty()) {
vermap = versionMapFields.get(PPPServer.default_version);
fieldList = vermap.get(service);
}
return fieldList;
}
public List<Map<String, Object>> querySQL(String sql) {
Map<String, String> query = new HashMap<>();
query.put("sql", sql);
return fieldMapper.querySQL(query);
}
}

View File

@ -0,0 +1,117 @@
package com.xhpc.pp.service;
import com.xhpc.pp.tx.ServiceParameter;
import com.xhpc.pp.tx.ServiceResult;
import com.xhpc.pp.tx.TxException;
import com.xhpc.pp.tx.logic.ServiceLogic;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Map;
@Component("ServiceMainLogic")
public class ServiceMainLogic {
protected Log log = LogFactory.getLog(getClass());
// 结构Map<serviceType,ServiceCommandLogic>
@Resource
private Map<String, ServiceLogic> serviceLogics;
public ServiceResult process(ServiceParameter param) {
ServiceResult result;
try {
// 调用具体业务逻辑的创建逻辑
ServiceLogic logic = getServiceLogic(param.getServiceName());
// 开启事务
startTransaction(param);
// 开始服务
result = logic.service(param);
// 提交事务
commitTransaction(param);
} catch (TxException e) {
log.error("服务请求失败:错误码[" + e.getReturnCode() + "],错误:{" + e.getMessage() + "}");
// 记录错误日志
// saveErrorLog(param, e);
try {
// 回滚事务
terminateTransaction(param);
result = new ServiceResult(e.getReturnCode(), e.getMessage());
} catch (Exception e1) {
result = new ServiceResult(null, e1.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
result = new ServiceResult(null, e.getMessage());
}
// 处理结果
return result;
}
// private void saveErrorLog(ServiceParameter param, TxException e) {
// Map<String, String> params = param.getParameters();
// String customerId = params.get("customerId");
// if (customerId == null || e.getMessage() == null)
// return;
//
// SysLog log = new SysLog();
// log.setSystemlogid(sequenceService.nextLogId());
// log.setCustomerid(Integer.parseInt(customerId));
// log.setLogtime(new Date());
// log.setOperationdescription(e.getMessage());
// log.setCreatetime(new Date());
// log.setUpdatetime(new Date());
//
// logService.save(log);
// }
/**
* 创建事务对象设置事务状态(已开始) 记录日志
*
* @param param
*/
private void startTransaction(ServiceParameter param) throws Exception {
//
}
/**
* 设置事务状态已完成保存到数据库
*
* @param param
*/
private void commitTransaction(ServiceParameter param) throws Exception {
}
/**
* 设置事务状态已失败保存到数据库
*
* @param param
*/
private void terminateTransaction(ServiceParameter param) throws Exception {
}
public ServiceLogic getServiceLogic(String serviceName) throws Exception {
if (serviceName == null || "".equals(serviceName))
throw new TxException("0101", "请求参数错误");
log.debug("获取ServiceCommandLogic,serviceName:" + serviceName);
ServiceLogic logic = serviceLogics.get(serviceName);
if (logic == null)
throw new TxException("0102", "请求的业务类型错误," + serviceName);
return logic;
}
}

View File

@ -0,0 +1,43 @@
package com.xhpc.pp.tx;
import com.xhpc.pp.service.ServiceMainLogic;
import com.xhpc.pp.utils.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.IOException;
import java.util.Map;
@Controller
@RequestMapping
public class ServiceController {
private static final String SESSIONID = "poleNo";
private static final String SERVICE_NAME = "serviceName";
@Autowired
private ServiceMainLogic servicemainLogic;
@RequestMapping(value = "/api")
@ResponseBody
public String index(@RequestBody Map<String, Object> req) throws IOException {
String poleNo = (String) req.get(SESSIONID);
String serviceName = (String) req.get(SERVICE_NAME);
ServiceParameter serviceParameter = new ServiceParameter(serviceName, poleNo, req);
ServiceResult result = servicemainLogic.process(serviceParameter);
if (result.getJson() != null) {
String body = JSONUtil.toJSONString(result.getJson());
return body;
} else {
return "";
}
}
}

View File

@ -0,0 +1,56 @@
package com.xhpc.pp.tx;
import java.io.Serializable;
import java.util.Map;
public class ServiceParameter implements Serializable {
private static final long serialVersionUID = 1L;
private String serviceName;
private String poleNo;
private String version;
private Map<String, Object> parameters;
public ServiceParameter(String serviceName, String poleNo, Map<String, Object> parameters) {
this.serviceName = serviceName;
this.parameters = parameters;
this.poleNo = poleNo;
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public Map<String, Object> getParameters() {
return parameters;
}
public void setParameters(Map<String, Object> parameters) {
this.parameters = parameters;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getPoleNo() {
return poleNo;
}
public void setPoleNo(String poleNo) {
this.poleNo = poleNo;
}
}

View File

@ -0,0 +1,52 @@
package com.xhpc.pp.tx;
import java.util.HashMap;
import java.util.Map;
public class ServiceResult {
public static final String RESULT_OK = "0000";
private byte[] binary;
private Object json;
public ServiceResult(String code, String body) {
Map<String, String> map = new HashMap<String, String>();
String messageCode = "0101";
if (code != null && code.trim().length() > 0) {
messageCode = code;
}
map.put("ErrCode", messageCode);
map.put("ErrMsg", body);
this.json = map;
}
public ServiceResult(Map<String, String> json) {
this.json = json;
}
public ServiceResult(Object json) {
this.json = json;
}
public ServiceResult() {
}
public ServiceResult(byte[] binary) {
this.binary = binary;
}
public Object getJson() {
return json;
}
public void setJson(Map<String, Object> json) {
this.json = json;
}
public byte[] getBinary() {
return binary;
}
}

View File

@ -0,0 +1,57 @@
package com.xhpc.pp.tx;
public class TxException extends Exception {
/**
* 缺少参数
*/
public static final TxException INVALID_PARAMETER = new TxException("1101", "缺少必要参数");
public static final TxException REGISTER_FAIL = new TxException("0103", "注册失败");
public static final TxException LOGIN_FAIL = new TxException("0104", "用户名或密码错误");
public static final TxException LOGIN_FAIL_NON_REG = new TxException("0105", "非APP注册用户请先注册后再登录");
public static final TxException LOGIN_FAIL_FREEZE = new TxException("0106", "用户处于冻结状态,暂不可用,请联系系统管理人员");
public static final TxException LOGIN_FAIL_SMS_CODE = new TxException("0107", "短信验证码不正确");
public static final TxException USER_NO_EXIST = new TxException("0108", "用户不存在");
public static final TxException SESSION_INVALID = new TxException("0001", "用户未登录或过期,请重新登录");
public static final TxException USER_BALANCE_LOCKED = new TxException("3001", "余额锁定,当前有未结束的充电操作。");
public static final TxException NO_DATA = new TxException("0002", "无数据");
private static final long serialVersionUID = 1L;
private String returnCode;
public TxException(String rtnCode, Throwable reason) {
super(rtnCode, reason);
this.returnCode = rtnCode;
}
public TxException(String rtnCode, String msg) {
super(msg);
this.returnCode = rtnCode;
}
public TxException(String rtnCode) {
this.returnCode = rtnCode;
}
public static TxException SERVICE_CALL_FIAL(String code, String error) {
return new TxException(code, error);
}
/**
* 参数错误
*/
public static TxException PARAMETER_INVALID(String error) {
return new TxException("1101", error);
}
/**
* 内部错误
*/
public static TxException INNER_ERROR(String msg) {
return new TxException("1111", msg);
}
public String getReturnCode() {
return returnCode;
}
}

View File

@ -0,0 +1,15 @@
package com.xhpc.pp.tx.logic;
import com.xhpc.pp.tx.ServiceParameter;
import com.xhpc.pp.tx.ServiceResult;
public interface ServiceLogic {
/**
* 实现具体服务
*
* @return
*/
ServiceResult service(ServiceParameter param) throws Exception;
}

View File

@ -0,0 +1,197 @@
package com.xhpc.pp.utils;
import com.ruoyi.common.core.exception.file.FileNameLengthLimitExceededException;
import com.ruoyi.common.core.exception.file.FileSizeLimitExceededException;
import com.ruoyi.common.core.exception.file.InvalidExtensionException;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.IdUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.file.MimeTypeUtils;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
/**
* 文件上传工具类
*
* @author ruoyi
*/
public class FileUploadUtils
{
/**
* 默认大小 50M
*/
public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
/**
* 默认的文件名最大长度 100
*/
public static final int DEFAULT_FILE_NAME_LENGTH = 100;
/**
* 根据文件路径上传
*
* @param baseDir 相对应用的基目录
* @param file 上传的文件
* @return 文件名称
* @throws IOException
*/
public static final String upload(String baseDir, MultipartFile file) throws IOException
{
try
{
return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
}
catch (Exception e)
{
throw new IOException(e.getMessage(), e);
}
}
/**
* 文件上传
*
* @param baseDir 相对应用的基目录
* @param file 上传的文件
* @param allowedExtension 上传文件类型
* @return 返回上传成功的文件名
* @throws FileSizeLimitExceededException 如果超出最大大小
* @throws FileNameLengthLimitExceededException 文件名太长
* @throws IOException 比如读写文件出错时
* @throws InvalidExtensionException 文件校验异常
*/
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
InvalidExtensionException
{
int fileNamelength = file.getOriginalFilename().length();
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
{
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
}
assertAllowed(file, allowedExtension);
String fileName = extractFilename(file);
File desc = getAbsoluteFile(baseDir, fileName);
file.transferTo(desc);
String pathFileName = getPathFileName(fileName);
return pathFileName;
}
/**
* 编码文件名
*/
public static final String extractFilename(MultipartFile file)
{
String fileName = file.getOriginalFilename();
String extension = getExtension(file);
fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
return fileName;
}
private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
{
File desc = new File(uploadDir + File.separator + fileName);
if (!desc.exists())
{
if (!desc.getParentFile().exists())
{
desc.getParentFile().mkdirs();
}
}
return desc.isAbsolute() ? desc : desc.getAbsoluteFile();
}
private static final String getPathFileName(String fileName) throws IOException
{
String pathFileName = "/" + fileName;
return pathFileName;
}
/**
* 文件大小校验
*
* @param file 上传的文件
* @throws FileSizeLimitExceededException 如果超出最大大小
* @throws InvalidExtensionException 文件校验异常
*/
public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
throws FileSizeLimitExceededException, InvalidExtensionException
{
long size = file.getSize();
if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE)
{
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
}
String fileName = file.getOriginalFilename();
String extension = getExtension(file);
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
{
if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
{
throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
fileName);
}
else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
{
throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
fileName);
}
else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
{
throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
fileName);
}
else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
{
throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
fileName);
}
else
{
throw new InvalidExtensionException(allowedExtension, extension, fileName);
}
}
}
/**
* 判断MIME类型是否是允许的MIME类型
*
* @param extension 上传文件类型
* @param allowedExtension 允许上传文件类型
* @return true/false
*/
public static final boolean isAllowedExtension(String extension, String[] allowedExtension)
{
for (String str : allowedExtension)
{
if (str.equalsIgnoreCase(extension))
{
return true;
}
}
return false;
}
/**
* 获取文件名的后缀
*
* @param file 表单文件
* @return 后缀名
*/
public static final String getExtension(MultipartFile file)
{
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
if (StringUtils.isEmpty(extension))
{
extension = MimeTypeUtils.getExtension(file.getContentType());
}
return extension;
}
}

View File

@ -0,0 +1,135 @@
package com.xhpc.pp.utils;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
public class JSONUtil {
private static ObjectMapper mapper = new ObjectMapper();
public static String toJSONString(Object o) throws JsonProcessingException {
/*return JSONObject.toJSONString(o);*/
return mapper.writeValueAsString(o);
}
public static <T> T readValue(String url, Class<T> clz) {
try {
URL u = new URL(url);
return mapper.readValue(u, clz);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static <T> T readValue(String url, String params, Class<T> clz) {
try {
String param = "?params=" + params;
URL u = new URL(url + param);
return mapper.readValue(u, clz);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
}
public static void writeTo(PrintWriter writer, Object value) {
try {
mapper.writeValue(writer, value);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static <T> T readParams(String params, Class<T> clz) {
try {
return mapper.readValue(params, clz);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static <T> T readParams(String params, JavaType collectionType) {
try {
return mapper.readValue(params, collectionType);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static <T> T readValue(InputStream content, Class<T> type) throws Exception {
return mapper.readValue(content, type);
}
public static <T> T readValue(String url, JavaType type) {
try {
return mapper.readValue(new URL(url), type);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 将一个对象转换成目标对象
*
* @param src
* @param dest
* @return
*/
public static <T> T copyProperties(Object src, Class<T> dest) throws Exception {
return JSON.parseObject(JSON.toJSONString(src), dest);
}
public static <T> T copyProperties(Object src, JavaType type) throws Exception {
return JSON.parseObject(JSON.toJSONString(src), type);
}
}

View File

@ -0,0 +1,83 @@
package com.xhpc.pp.utils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
/**
* 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicaitonContext.
*/
@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
/**
* 取得存储在静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
assertContextInjected();
return applicationContext;
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
assertContextInjected();
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
assertContextInjected();
return applicationContext.getBean(requiredType);
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
public static void clearHolder() {
if (logger.isDebugEnabled()){
logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
}
applicationContext = null;
}
/**
* 实现ApplicationContextAware接口, 注入Context到静态变量中.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext;
}
/**
* 实现DisposableBean接口, 在Context关闭时清理静态变量.
*/
@Override
public void destroy() throws Exception {
SpringContextHolder.clearHolder();
}
/**
* 检查ApplicationContext不为空.
*/
private static void assertContextInjected() {
Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
}
}

View File

@ -0,0 +1,148 @@
package com.xhpc.pp.utils.security;
import com.ruoyi.common.core.utils.sign.Base64;
import java.io.*;
/** */
/**
* <p>
* BASE64编码解码工具包
* </p>
* <p>
* 依赖javabase64-1.3.1.jar
* </p>
*
* @author IceWee
* @version 1.0
* @date 2012-5-19
*/
public class Base64Utils {
/** */
/**
* 文件读取缓冲区大小
*/
private static final int CACHE_SIZE = 1024;
/** */
/**
* <p>
* BASE64字符串解码为二进制数据
* </p>
*
* @param base64
* @return
* @throws Exception
*/
public static byte[] decode(String base64) throws Exception {
return Base64.decode(base64);
}
/** */
/**
* <p>
* 二进制数据编码为BASE64字符串
* </p>
*
* @param bytes
* @return
* @throws Exception
*/
public static String encode(byte[] bytes) throws Exception {
return new String(Base64.encode(bytes));
}
/** */
/**
* <p>
* 将文件编码为BASE64字符串
* </p>
* <p>
* 大文件慎用可能会导致内存溢出
* </p>
*
* @param filePath 文件绝对路径
* @return
* @throws Exception
*/
public static String encodeFile(String filePath) throws Exception {
byte[] bytes = fileToByte(filePath);
return encode(bytes);
}
/** */
/**
* <p>
* BASE64字符串转回文件
* </p>
*
* @param filePath 文件绝对路径
* @param base64 编码字符串
* @throws Exception
*/
public static void decodeToFile(String filePath, String base64) throws Exception {
byte[] bytes = decode(base64);
byteArrayToFile(bytes, filePath);
}
/** */
/**
* <p>
* 文件转换为二进制数组
* </p>
*
* @param filePath 文件路径
* @return
* @throws Exception
*/
public static byte[] fileToByte(String filePath) throws Exception {
byte[] data = new byte[0];
File file = new File(filePath);
if (file.exists()) {
FileInputStream in = new FileInputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
byte[] cache = new byte[CACHE_SIZE];
int nRead = 0;
while ((nRead = in.read(cache)) != -1) {
out.write(cache, 0, nRead);
out.flush();
}
out.close();
in.close();
data = out.toByteArray();
}
return data;
}
/** */
/**
* <p>
* 二进制数据写文件
* </p>
*
* @param bytes 二进制数据
* @param filePath 文件生成目录
*/
public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception {
InputStream in = new ByteArrayInputStream(bytes);
File destFile = new File(filePath);
if (!destFile.getParentFile().exists()) {
destFile.getParentFile().mkdirs();
}
destFile.createNewFile();
OutputStream out = new FileOutputStream(destFile);
byte[] cache = new byte[CACHE_SIZE];
int nRead = 0;
while ((nRead = in.read(cache)) != -1) {
out.write(cache, 0, nRead);
out.flush();
}
out.close();
in.close();
}
}

View File

@ -0,0 +1,76 @@
package com.xhpc.pp.utils.security;
public class CRCCalculator {
public static String ModbusCRC(byte[] pData, int len) {
int crc = 0xFFFF;
for (int pos = 0; pos < len; pos++) {
crc ^= (int)pData[pos] & 0xFF; // XOR byte into least sig. byte of crc
for (int i = 8; i != 0; i--) { // Loop over each bit
if ((crc & 0x0001) != 0) { // If the LSB is set
crc >>= 1; // Shift right and XOR 0xA001
crc ^= 0xA001;
}
else // Else LSB is not set
crc >>= 1; // Just shift right
}
}
// Revert hi-lo
crc = ((crc & 0xFF00) >> 8) | ((crc & 0x00FF) << 8);
return String.format("%04X", crc);
}
public static int byteArrayToInt(byte[] b) {
return b[3] & 0xFF |
(b[2] & 0xFF) << 8 |
(b[1] & 0xFF) << 16 |
(b[0] & 0xFF) << 24;
}
public static byte[] intToByteArray(int a) {
return new byte[]{
(byte) ((a >> 24) & 0xFF),
(byte) ((a >> 16) & 0xFF),
(byte) ((a >> 8) & 0xFF),
(byte) (a & 0xFF)
};
}
private static byte[] hi = {
(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40
};
private static byte lo[] = {
(byte) 0x00, (byte) 0xC0, (byte) 0xC1, (byte) 0x01, (byte) 0xC3, (byte) 0x03, (byte) 0x02, (byte) 0xC2, (byte) 0xC6, (byte) 0x06, (byte) 0x07, (byte) 0xC7, (byte) 0x05, (byte) 0xC5, (byte) 0xC4, (byte) 0x04,
(byte) 0xCC, (byte) 0x0C, (byte) 0x0D, (byte) 0xCD, (byte) 0x0F, (byte) 0xCF, (byte) 0xCE, (byte) 0x0E, (byte) 0x0A, (byte) 0xCA, (byte) 0xCB, (byte) 0x0B, (byte) 0xC9, (byte) 0x09, (byte) 0x08, (byte) 0xC8,
(byte) 0xD8, (byte) 0x18, (byte) 0x19, (byte) 0xD9, (byte) 0x1B, (byte) 0xDB, (byte) 0xDA, (byte) 0x1A, (byte) 0x1E, (byte) 0xDE, (byte) 0xDF, (byte) 0x1F, (byte) 0xDD, (byte) 0x1D, (byte) 0x1C, (byte) 0xDC,
(byte) 0x14, (byte) 0xD4, (byte) 0xD5, (byte) 0x15, (byte) 0xD7, (byte) 0x17, (byte) 0x16, (byte) 0xD6, (byte) 0xD2, (byte) 0x12, (byte) 0x13, (byte) 0xD3, (byte) 0x11, (byte) 0xD1, (byte) 0xD0, (byte) 0x10,
(byte) 0xF0, (byte) 0x30, (byte) 0x31, (byte) 0xF1, (byte) 0x33, (byte) 0xF3, (byte) 0xF2, (byte) 0x32, (byte) 0x36, (byte) 0xF6, (byte) 0xF7, (byte) 0x37, (byte) 0xF5, (byte) 0x35, (byte) 0x34, (byte) 0xF4,
(byte) 0x3C, (byte) 0xFC, (byte) 0xFD, (byte) 0x3D, (byte) 0xFF, (byte) 0x3F, (byte) 0x3E, (byte) 0xFE, (byte) 0xFA, (byte) 0x3A, (byte) 0x3B, (byte) 0xFB, (byte) 0x39, (byte) 0xF9, (byte) 0xF8, (byte) 0x38,
(byte) 0x28, (byte) 0xE8, (byte) 0xE9, (byte) 0x29, (byte) 0xEB, (byte) 0x2B, (byte) 0x2A, (byte) 0xEA, (byte) 0xEE, (byte) 0x2E, (byte) 0x2F, (byte) 0xEF, (byte) 0x2D, (byte) 0xED, (byte) 0xEC, (byte) 0x2C,
(byte) 0xE4, (byte) 0x24, (byte) 0x25, (byte) 0xE5, (byte) 0x27, (byte) 0xE7, (byte) 0xE6, (byte) 0x26, (byte) 0x22, (byte) 0xE2, (byte) 0xE3, (byte) 0x23, (byte) 0xE1, (byte) 0x21, (byte) 0x20, (byte) 0xE0,
(byte) 0xA0, (byte) 0x60, (byte) 0x61, (byte) 0xA1, (byte) 0x63, (byte) 0xA3, (byte) 0xA2, (byte) 0x62, (byte) 0x66, (byte) 0xA6, (byte) 0xA7, (byte) 0x67, (byte) 0xA5, (byte) 0x65, (byte) 0x64, (byte) 0xA4,
(byte) 0x6C, (byte) 0xAC, (byte) 0xAD, (byte) 0x6D, (byte) 0xAF, (byte) 0x6F, (byte) 0x6E, (byte) 0xAE, (byte) 0xAA, (byte) 0x6A, (byte) 0x6B, (byte) 0xAB, (byte) 0x69, (byte) 0xA9, (byte) 0xA8, (byte) 0x68,
(byte) 0x78, (byte) 0xB8, (byte) 0xB9, (byte) 0x79, (byte) 0xBB, (byte) 0x7B, (byte) 0x7A, (byte) 0xBA, (byte) 0xBE, (byte) 0x7E, (byte) 0x7F, (byte) 0xBF, (byte) 0x7D, (byte) 0xBD, (byte) 0xBC, (byte) 0x7C,
(byte) 0xB4, (byte) 0x74, (byte) 0x75, (byte) 0xB5, (byte) 0x77, (byte) 0xB7, (byte) 0xB6, (byte) 0x76, (byte) 0x72, (byte) 0xB2, (byte) 0xB3, (byte) 0x73, (byte) 0xB1, (byte) 0x71, (byte) 0x70, (byte) 0xB0,
(byte) 0x50, (byte) 0x90, (byte) 0x91, (byte) 0x51, (byte) 0x93, (byte) 0x53, (byte) 0x52, (byte) 0x92, (byte) 0x96, (byte) 0x56, (byte) 0x57, (byte) 0x97, (byte) 0x55, (byte) 0x95, (byte) 0x94, (byte) 0x54,
(byte) 0x9C, (byte) 0x5C, (byte) 0x5D, (byte) 0x9D, (byte) 0x5F, (byte) 0x9F, (byte) 0x9E, (byte) 0x5E, (byte) 0x5A, (byte) 0x9A, (byte) 0x9B, (byte) 0x5B, (byte) 0x99, (byte) 0x59, (byte) 0x58, (byte) 0x98,
(byte) 0x88, (byte) 0x48, (byte) 0x49, (byte) 0x89, (byte) 0x4B, (byte) 0x8B, (byte) 0x8A, (byte) 0x4A, (byte) 0x4E, (byte) 0x8E, (byte) 0x8F, (byte) 0x4F, (byte) 0x8D, (byte) 0x4D, (byte) 0x4C, (byte) 0x8C,
(byte) 0x44, (byte) 0x84, (byte) 0x85, (byte) 0x45, (byte) 0x87, (byte) 0x47, (byte) 0x46, (byte) 0x86, (byte) 0x82, (byte) 0x42, (byte) 0x43, (byte) 0x83, (byte) 0x41, (byte) 0x81, (byte) 0x80, (byte) 0x40
};
}

View File

@ -0,0 +1,5 @@
package com.xhpc.pp.utils.security;
public class DES {
}

View File

@ -0,0 +1,168 @@
package com.xhpc.pp.utils.security;
import org.apache.commons.lang3.ArrayUtils;
public class HexUtils {
/**
* 字节数据转字符串专用集合
*/
private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
'F'};
public static String toHex(byte[] data) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < data.length; i++) {
// 取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]);
// 取出字节的低四位 作为索引得到相应的十六进制标识符
stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
}
return stringBuilder.toString();
}
public static String toHex(byte[] data, int start, int end) {
if (data == null || data.length < end)
return "";
return toHex(ArrayUtils.subarray(data, start, end));
}
public static String toString(byte[] data) {
return new String(data);
}
public static String toString(byte[] data, int start, int end) {
if (data == null || data.length < end)
return "";
return toString(ArrayUtils.subarray(data, start, end));
}
public static int toInteger(byte[] data, int start, int end) {
if (data == null || data.length < end)
return 0;
return Integer.decode("0x" + toHex(data, start, end));
}
public static byte[] toBytes(String hex) {
hex = hex.trim();
if (hex == null || hex.length() == 0 || hex.length() % 2 != 0)
return null;
byte[] b = new byte[hex.length() / 2];
for (int i = 0; i < hex.length(); i = i + 2) {
b[i / 2] = Integer.decode("0x" + hex.substring(i, i + 2)).byteValue();
}
return b;
}
public static byte[] stringToBytes(String str, int len) {
byte[] data = str.getBytes();
if (data.length > len)
return data;
for (int i = data.length; i < len; i++)
data = ArrayUtils.add(data, (byte) 0);
return data;
}
public static String toIntString(String hex) {
return toIntString(hex, 4);
}
public static String toIntString(String hex, int len) {
if (hex == null || hex.length() == 0 || hex.length() % len != 0)
return null;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < hex.length(); i = i + len) {
sb.append(String.format("%0" + len + "d", byte2int(toBytes(hex.substring(i, i + len)))));
}
return sb.toString();
}
public static byte[] toIntBytes(String num, int len) {
if (num == null || num.length() == 0 || num.length() % len != 0)
return null;
byte[] result = new byte[0];
for (int i = 0; i < num.length(); i = i + len) {
int n = Integer.parseInt(num.substring(i, i + len));
result = ArrayUtils.addAll(result, toIntBytes(n, len / 2));
}
return result;
}
public static byte[] toIntBytes(int n, int len) {
byte[] b = new byte[len];
for (int i = 0; i < len; i++) {
b[i] = (byte) (n >> i * 8 & 0xff);
}
return b;
}
public static int byte2int(byte[] b) {
int res = 0;
int bLen = b.length;
if (bLen < 5) {// int 最大到4个字节
for (int i = 0; i < bLen; i++) {
res += (b[i] & 0xFF) << (8 * i);
}
}
return res;
}
public static byte[] toLongBytes(long n) {
byte[] b = new byte[4];
for (int i = 0; i < 4; i++) {
b[i] = (byte) ((n >> i * 8) & 0xff);
}
return b;
}
// 使用小端 字节index 0 对应 int 的最后一个字节
public static long byte2Long(byte[] b) {
long res = 0;
int bLen = b.length;
// int 最大到4个字节
if (bLen < 9) {
for (int i = 0; i < bLen; i++) {
res += (b[i] & 0xFFL) << 8 * i;
}
}
return res;
}
public static void main(String[] args) {
System.out.println(toIntString("E80373000E02E903", 4));
System.out.println(toHex(toIntBytes("1000011505261001", 4)));
System.out.println(toIntBytes("0016537797330272", 4));
// System.out.println(toIntString("32FFD505484B323441260443AAAAAAAA",8));
System.out.println(toHex(toLongBytes(1000000L)));
System.out.println(byte2Long(toBytes("20090080")));
System.out.println(0x80 & 0xff);
System.out.println(String.format("%032d", 123456));
}
}

View File

@ -0,0 +1,118 @@
package com.xhpc.pp.utils.security;
import org.apache.commons.codec.digest.DigestUtils;
import java.io.UnsupportedEncodingException;
import java.security.SignatureException;
import java.util.*;
public class MD5 {
/**
* 签名字符串
*
* @param text 需要签名的字符串
* @param key 密钥
* @param input_charset 编码格式
* @return 签名结果
*/
public static String sign(String text, String key, String input_charset) {
text = text + key;
return DigestUtils.md5Hex(getContentBytes(text, input_charset));
}
public static String sign(String text, String key) {
return sign(text, key, "utf-8").toUpperCase();
}
/**
* 签名字符串
*
* @param text 需要签名的字符串
* @param sign 签名结果
* @param key 密钥
* @return 签名结果
*/
public static boolean verify(String text, String sign, String key) {
text = text + key;
String mysign = DigestUtils.md5Hex(getContentBytes(text, "UTF-8"));
if (mysign.equals(sign)) {
return true;
} else {
return false;
}
}
/**
* @param content
* @param charset
* @return
* @throws SignatureException
* @throws UnsupportedEncodingException
*/
private static byte[] getContentBytes(String content, String charset) {
if (charset == null || "".equals(charset)) {
return content.getBytes();
}
try {
return content.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
}
}
/**
* 除去数组中的空值和签名参数
*
* @param sArray 签名参数组
* @return 去掉空值与签名参数后的新签名参数组
*/
public static Map<String, String> paraFilter(Map<String, String> sArray) {
Map<String, String> result = new HashMap<String, String>();
if (sArray == null || sArray.size() <= 0) {
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key);
if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
|| key.equalsIgnoreCase("sign_type")) {
continue;
}
result.put(key, value);
}
return result;
}
/**
* 把数组所有元素排序并按照参数=参数值的模式用&字符拼接成字符串
*
* @param params 需要排序并参与字符拼接的参数组
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, String> params) {
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);
String prestr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {//拼接时不包括最后一个&字符
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
}
}

View File

@ -0,0 +1,10 @@
Spring Boot Version: ${spring-boot.version}
Spring Application Name: ${spring.application.name}
_ __ _ _
(_) / _|(_)| |
_ __ _ _ ___ _ _ _ ______ | |_ _ | | ___
| '__|| | | | / _ \ | | | || ||______|| _|| || | / _ \
| | | |_| || (_) || |_| || | | | | || || __/
|_| \__,_| \___/ \__, ||_| |_| |_||_| \___|
__/ |
|___/

View File

@ -0,0 +1,29 @@
ppsvc:
server: 0.0.0.0
port: 8886
# Tomcat
server:
port: ${random.int(1300,1400)}
# Spring
spring:
application:
# 应用名称
name: xhpc-power-pole
profiles:
# 环境配置
active: dev
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 127.0.0.1:8848
config:
# 配置中心地址
server-addr: 127.0.0.1:8848
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/xphc-power-pole" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.xhpc" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
</configuration>

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xhpc.pp.mapper.ServiceFieldMapper">
<resultMap id="BaseResultMap" type="com.xhpc.pp.domain.ServiceField">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="service_name" property="serviceName" jdbcType="VARCHAR"/>
<result column="version" property="version" jdbcType="VARCHAR"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="code" property="code" jdbcType="VARCHAR"/>
<result column="len" property="len" jdbcType="INTEGER"/>
<result column="seq" property="seq" jdbcType="INTEGER"/>
<result column="remark" property="remark" jdbcType="VARCHAR"/>
<result column="data_type" property="dataType" jdbcType="VARCHAR"/>
</resultMap>
<sql id="Base_Column_List">
id
, service_name, version, name, code, len, seq, remark, data_type
</sql>
<select id="querySQL" parameterType="java.util.Map" resultType="java.util.Map">
${sql}
</select>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long">
select
<include refid="Base_Column_List"/>
from service_field
where id = #{id,jdbcType=BIGINT}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
delete
from service_field
where id = #{id,jdbcType=BIGINT}
</delete>
<insert id="insert" parameterType="com.xhpc.pp.domain.ServiceField">
insert into service_field (id, service_name, version,
name, code, len, seq,
remark)
values (#{id,jdbcType=BIGINT}, #{serviceName,jdbcType=VARCHAR}, #{version,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR}, #{code,jdbcType=VARCHAR}, #{len,jdbcType=INTEGER}, #{seq,jdbcType=INTEGER},
#{remark,jdbcType=VARCHAR})
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.xhpc.pp.domain.ServiceField">
update service_field
<set>
<if test="serviceName != null">
service_name = #{serviceName,jdbcType=VARCHAR},
</if>
<if test="version != null">
version = #{version,jdbcType=VARCHAR},
</if>
<if test="name != null">
name = #{name,jdbcType=VARCHAR},
</if>
<if test="code != null">
code = #{code,jdbcType=VARCHAR},
</if>
<if test="len != null">
len = #{len,jdbcType=INTEGER},
</if>
<if test="seq != null">
seq = #{seq,jdbcType=INTEGER},
</if>
<if test="remark != null">
remark = #{remark,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=BIGINT}
</update>
<select id="query" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from service_field
where 1 = 1
<if test="serviceName != null">
and service_name = #{serviceName,jdbcType=VARCHAR}
</if>
<if test="version != null">
and version = #{version,jdbcType=VARCHAR}
</if>
<if test="name != null">
and name = #{name,jdbcType=VARCHAR}
</if>
<if test="code != null">
and code = #{code,jdbcType=VARCHAR}
</if>
order by version asc, service_name asc, seq asc
</select>
</mapper>