This commit is contained in:
yidao620 2018-02-26 19:05:53 +08:00
commit 4d57c022c6
534 changed files with 96924 additions and 0 deletions

14
.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
# 此为注释– 将被Git 忽略
# /结尾表示是目录,忽略目录和目录下的所有件
# /开头表示根目录,否则是.gitignore的相对目录
# !开头表示反选
.idea/
target/
*.iml
*.ipr
*.iws
*.log
.svn/
.project
rebel.xml
.rebel-remote.xml.*

20
LICENSE Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2018 Xiong Neng
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

88
README.md Normal file
View File

@ -0,0 +1,88 @@
## SpringBoot 全家桶
Spring Boot 现在已经成为Java 开发领域的一颗璀璨明珠,它本身是包容万象的,可以跟各种技术集成。
本项目对目前Web开发中常用的各个技术通过和SpringBoot的集成并且对各种技术通过“一篇博客 + 一个可运行项目”的形式来详细说明。
每个子项目都会使用最小依赖,大家拿来即可使用,自己可以根据业务需求自由组合搭配不同的技术构建项目。
## 项目简介
![](https://xnstatic-1253397658.file.myqcloud.com/SpringBootBucket.png)
## 子项目列表
每个项目一篇博客文章的详细讲解,点击链接可以查看文章:
* springboot-thymeleaf [集成Thymeleaf构建Web应用](https://www.xncoding.com/2017/07/01/spring/sb-thymeleaf.html)
* springboot-mybatis [集成MyBatis](https://www.xncoding.com/2017/07/02/spring/sb-mybatis.html)
* springboot-hibernate [集成Hibernate](https://www.xncoding.com/2017/07/03/spring/sb-hibernate.html)
* springboot-mongodb [集成MongoDB](https://www.xncoding.com/2017/07/04/spring/sb-mongodb.html)
* springboot-restful [实现RESTful接口](https://www.xncoding.com/2017/07/05/spring/sb-restful.html)
* springboot-resttemplate [使用RestTemplate](https://www.xncoding.com/2017/07/06/spring/sb-restclient.html)
* springboot-shiro [集成Shiro权限管理](https://www.xncoding.com/2017/07/07/spring/sb-shiro.html)
* springboot-swagger2 [集成Swagger2](https://www.xncoding.com/2017/07/08/spring/sb-swagger2.html)
* springboot-jwt [集成JWT实现接口权限认证](https://www.xncoding.com/2017/07/09/spring/sb-jwt.html)
* springboot-multisource[多数据源配置](https://www.xncoding.com/2017/07/10/spring/sb-multisource.html)
* springboot-schedule [定时任务](https://www.xncoding.com/2017/07/12/spring/sb-schedule.html)
* springboot-websocket [使用WebScoket实时通信](https://www.xncoding.com/2017/07/15/spring/sb-websocket.html)
* springboot-socketio [集成SocketIO实时通信](https://www.xncoding.com/2017/07/16/spring/sb-socketio.html)
* springboot-async [异步线程池](https://www.xncoding.com/2017/07/20/spring/sb-async.html)
* springboot-starter [教你自己写starter](https://www.xncoding.com/2017/07/22/spring/sb-starter.html)
* springboot-aop [使用AOP](https://www.xncoding.com/2017/07/24/spring/sb-aop.html)
* springboot-transaction [声明式事务](https://www.xncoding.com/2017/07/26/spring/sb-transaction.html)
* springboot-cache [使用缓存](https://www.xncoding.com/2017/07/28/spring/sb-cache.html)
* springboot-redis [Redis数据库](https://www.xncoding.com/2017/07/30/spring/sb-redis.html)
* springboot-batch [批处理](https://www.xncoding.com/2017/08/01/spring/sb-batch.html)
* springboot-rabbitmq [集成消息队列RabbitMQ](https://www.xncoding.com/2017/08/06/spring/sb-rabbitmq.html)
* springboot-echarts [集成Echarts导出图片](https://www.xncoding.com/2017/08/19/spring/sb-echarts.html)
* app-manage [一个完整的Web后台管理系统组合使用了多种技术]
* app-manage-api [同时实现了需要认证授权访问的RESTful API接口和WebSocket接口]
## 环境
* maven latest
* jdk1.8
* spring boot 1.5.9 release
* intellij idea
* mysql5.6
* git
* nginx
## 运行
每个子项目都可以单独运行都是打包成jar包后通过使用内置jetty容器执行有3种方式运行。
1. 在IDEA里面直接运行Application.java的main函数。
2. 另一种方式是执行`mvn clean package`命令后传到linux服务器上面通过命令`java -jar xxx.jar`方式运行
3. 在linux服务器上面配置好jdk、maven、git命令后通过`git clone sb-xxx`拉取工程后,执行`./run.sh start test`命令来执行
每个子项目有自己的README.md文件告诉你该怎么初始化环境比如准备好数据库SQL文件等。
另外如果你需要打包成war包放到tomcat容器中运行可修改pom.xml文件将打包类型从jar改成war打包后再放到容器中运行
``` xml
<modelVersion>4.0.0</modelVersion>
<artifactId>sb-cache</artifactId>
<packaging>war</packaging>
```
## 后续计划
1. 集成OAuth2认证
1. 集成QQ、微信、新浪微博第三方登录配合shiro使用
1. 集成网络爬虫框架
## 问题反馈
1. 欢迎提issue一起完善这个项目
1. Email: yidao620@gmail.com
1. 个人主站: https://www.xncoding.com/
## 许可证
Copyright (c) 2018 [Xiong Neng](https://www.xncoding.com/)
基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>

17
app-manage-api/.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
# 此为注释– 将被Git 忽略
# /结尾表示是目录,忽略目录和目录下的所有件
# /开头表示根目录,否则是.gitignore的相对目录
# !开头表示反选
.idea/
target/
*.iml
*.ipr
*.iws
*.log
.svn/
.project
rebel.xml
.rebel-remote.xml.*
swagger.json
swagger.adoc

20
app-manage-api/LICENSE Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2018 Xiong Neng
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

63
app-manage-api/README.md Normal file
View File

@ -0,0 +1,63 @@
## 简介
同时实现了RESTful API接口和WebSocket接口并且都需要授权才能访问授权机制基于Token实现技术是JWT+Shiro
访问RESTful API接口或连接到WebSocket服务之前都需要先调用登录接口拿到Token。
## JWT + Shiro实现接口认证
SpringBoot + JWT + Shiro实现RESTful API的授权访问
## WeSocket长连接
Socket.IO服务器端和客户端使用Java语言实现用于和POS机进行长连接的WebSocket通信。
服务器端可以实时将消息推送给POS端比如机具解绑操作以此来取代机具管理系统中客户端轮询机制。
Sockt.io官网<https://socket.io/>
服务器端使用 [netty-socketio](https://github.com/mrniko/netty-socketio)
客户端使用 [socket.io-client-java](https://github.com/socketio/socket.io-client-java)
### WebSocket js客户端测试
```
com.enzhico.pos.socket.server.ChatLauncher - /client/html/index.html
com.enzhico.pos.socket.server.EventChatLauncher - /client/html/event-index.html
com.enzhico.pos.socket.server.SslChatLauncher - /client/html/ssl-event-index.html
com.enzhico.pos.socket.server.NamespaceChatLauncher - /client/html/namespace-index.html
com.enzhico.pos.socket.server.AckChatLauncher - /client/html/ack-index.html
com.enzhico.pos.socket.server.BinaryEventLauncher - /client/html/binary-event-index.html
```
### WebSocket Java客户端测试
```
服务器:
com.enzhico.pos.socket.server.SocketServer
客户端:
com.enzhico.pos.socket.client.SocketClient
```
### 广播消息中的namespace和room
如果不指定namespace有个默认namespace默认room房间在namespace下面。
netty-socketio服务器端完整实现了所有Socket.IO功能而客户端再浏览器下面表现完美
但是socket.io-client-java只要加上namespace就报错不过它的room广播功能可用。
所以目前的做法是对于每个项目下的APP加入到对应applicationId房间中可实现房间广播。
## JWT + Netty-SocketIO实现WebSocket的授权访问
对于需要进行认证的接口通过JWT的Token方式实现了用户认证访问。
## 运行
该工程和app-manage工程配套请参考app-manage工程的数据库初始化schema.sql
## 许可证
Copyright (c) 2018 Xiong Neng
基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>

274
app-manage-api/pom.xml Normal file
View File

@ -0,0 +1,274 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xncoding</groupId>
<artifactId>app-manage-api</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>app-manage-api</name>
<description>JWT实现RESTful API接口认证和Socket.IO认证</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<netty.version>4.1.19.Final</netty.version>
<druid.version>1.1.2</druid.version>
<mysql-connector.version>8.0.7-dmr</mysql-connector.version>
<mybatis-plus.version>2.1.8</mybatis-plus.version>
<mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- MyBatis plus增强和springboot的集成-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatisplus-spring-boot-starter</artifactId>
<version>${mybatisplus-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.6</version>
</dependency>
<!-- shiro 权限控制 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- shiro ehcache (shiro缓存)-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- netty-socketio-->
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.13</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-resolver</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-epoll</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-unix-common</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.socket</groupId>
<artifactId>socket.io-client</artifactId>
<version>1.0.0</version>
</dependency>
<!-- swagger2 集成-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>com.xncoding</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.pegdown</groupId>
<artifactId>pegdown</artifactId>
<version>1.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.github.swagger2markup</groupId>
<artifactId>swagger2markup</artifactId>
<version>1.3.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<!--<proc>none</proc>-->
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<systemPropertyVariables>
<swaggerOutputDir>${project.basedir}/src/main/resources/swagger</swaggerOutputDir>
<asciiDocOutputDir>${project.basedir}/src/main/resources/swagger/swagger</asciiDocOutputDir>
</systemPropertyVariables>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>

72
app-manage-api/run.sh Normal file
View File

@ -0,0 +1,72 @@
#!/bin/bash
# 项目自动更新脚本
# 先clone相应的分支下来
# git clone ssh://git@120.24.173.142:7999/xxx.git
# 远程调试启动:
# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &
function start {
profile="$1"
echo "启动环境profile=${profile}"
jarfile=$(ls target/*.jar)
if [[ "$?" == "0" ]]; then
stop $profile $jarfile
fi
branch=$(git branch |awk '{print $2}')
git pull origin ${branch}
echo "更新完代码开始重新打包"
mvn clean && mvn clean && mvn package -DskipTests=true
if [[ "$?" != "0" ]]; then
echo "编译出错,退出!"
exit 1
fi
echo "nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &"
nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &
echo "启动应用中,请查看日志文件..."
}
function stop {
profile="$1"
jarfile="$2"
ps aux | grep "${jarfile}" | grep "spring.profiles.active=${profile}" | grep -v grep > /dev/null
if [[ "$?" == "0" ]]; then
echo "该应用还在跑,我先停了它"
pid=$(ps aux | grep "${jarfile}" | grep "spring.profiles.active=${profile}" | grep -v grep |awk '{print $2}')
if [[ "$pid" != "" ]]; then
kill -9 $pid
fi
echo "停止应用成功..."
fi
}
if [[ "$1" == "start" ]]; then
if [[ "$#" < 2 ]]; then
echo "请输入正确参数:./epay.sh start {profile}"
exit 1
fi
profile="$2"
if [[ "$profile" != "dev" && "$profile" != "test" && "$profile" != "show" && "$profile" != "production" ]]; then
echo "参数错误请输入正确的profile参数使用方法"
echo "./epay.sh start {profile} ==> 启动应用,{profile}取值dev|test|show|production"
exit 1
fi
start "${profile}"
elif [[ "$1" == "stop" ]]; then
if [[ "$#" < 2 ]]; then
echo "请输入正确参数:./epay.sh stop {profile}"
exit 1
fi
profile="$2"
if [[ "$profile" != "dev" && "$profile" != "test" && "$profile" != "show" && "$profile" != "production" ]]; then
echo "参数错误请输入正确的profile参数使用方法"
echo "./epay.sh stop {profile} ==> 停止应用,{profile}取值dev|test|show|production"
exit 1
fi
jarfile=$(ls target/*.jar)
stop $profile $jarfile
else
echo "参数错误,使用方法:{}参数是必填的,[]参数可选"
echo "./epay.sh start {profile} ==> 启动应用,{profile}取值dev|test|show|production"
echo "./epay.sh stop {profile} ==> 停止应用,{profile}取值dev|test|show|production"
exit 1
fi

View File

@ -0,0 +1,12 @@
package com.enzhico.jwt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@ -0,0 +1,49 @@
package com.enzhico.jwt.api;
import com.enzhico.jwt.api.model.BaseResponse;
import io.swagger.annotations.Api;
import org.apache.shiro.ShiroException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
/**
* 注意这个统一异常处理器只对认证过的用户调用接口中的异常有作用对AuthenticationException没有用
*/
@RestControllerAdvice
@Api(value = "机具管理API接口类", tags = "机具管理接口", description = "提供POS机的入网和监控的统一管理")
public class ExceptionController {
// 捕捉shiro的异常
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(ShiroException.class)
public BaseResponse handle401(ShiroException e) {
return new BaseResponse(false, "shiro的异常", null);
}
// 捕捉UnauthorizedException
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(UnauthorizedException.class)
public BaseResponse handle401() {
return new BaseResponse(false, "UnauthorizedException", null);
}
// 捕捉其他所有异常
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public BaseResponse globalException(HttpServletRequest request, Throwable ex) {
return new BaseResponse(false, "其他异常", null);
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
return HttpStatus.valueOf(statusCode);
}
}

View File

@ -0,0 +1,87 @@
package com.enzhico.jwt.api;
import com.enzhico.jwt.api.model.BaseResponse;
import com.enzhico.jwt.api.model.LoginParam;
import com.enzhico.jwt.common.util.JWTUtil;
import com.enzhico.jwt.dao.entity.ManagerInfo;
import com.enzhico.jwt.service.ManagerInfoService;
import com.enzhico.jwt.shiro.ShiroKit;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
import javax.annotation.Resource;
/**
* 登录接口类
*/
@Api(value = "登录请求接口类", tags = "登录", description = "用户请求登录获取Token")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "请求已完成"),
@ApiResponse(code = 201, message = "资源成功被创建"),
@ApiResponse(code = 400, message = "请求中有语法问题,或不能满足请求"),
@ApiResponse(code = 401, message = "未授权客户机访问数据"),
@ApiResponse(code = 403, message = "服务器接受请求,但是拒绝处理"),
@ApiResponse(code = 404, message = "服务器找不到给定的资源;文档不存在"),
@ApiResponse(code = 500, message = "服务器出现异常")}
)
@RestController
public class LoginController {
@Resource
private ManagerInfoService managerInfoService;
private static final Logger _logger = LoggerFactory.getLogger(LoginController.class);
@ApiOperation(value = "登录认证接口", notes = "不管是接口还是WebSocket连接都需要先调用此接口拿到Token然后再通过Token调用相应接口最好使用HTTPS协议。调用RESTful API方式不需要传后面两个参数如果通过WebSocket连接需要传递", produces = "application/json")
@PostMapping("/login")
public BaseResponse<String> login(@RequestHeader(name="Content-Type", defaultValue = "application/json") String contentType,
@ApiParam(value = "登录参数") @RequestBody LoginParam loginParam) {
_logger.info("用户请求登录获取Token");
String username = loginParam.getUsername();
String password = loginParam.getPassword();
String appid = loginParam.getAppid();
String imei = loginParam.getImei();
ManagerInfo user = managerInfoService.findByUsername(username);
//用户名+随机数
String salt = user.getSalt();
//原密码
String encodedPassword = ShiroKit.md5(password, username + salt);
if (user.getPassword().equals(encodedPassword)) {
if (StringUtils.isNotEmpty(appid) && StringUtils.isNotEmpty(imei)) {
return new BaseResponse<>(true, "Login success", JWTUtil.signSocket(username, encodedPassword, appid, imei));
}
return new BaseResponse<>(true, "Login success", JWTUtil.sign(username, encodedPassword));
} else {
throw new UnauthorizedException();
}
}
@ApiOperation(value = "推送消息登录认证接口", notes = "这里的密码是加密后的密码", produces = "application/json")
@PostMapping("/notifyLogin")
public BaseResponse<String> notifyLogin(@RequestHeader(name="Content-Type", defaultValue = "application/json") String contentType,
@ApiParam(value = "登录参数") @RequestBody LoginParam loginParam) {
_logger.info("登录用户推送请求登录获取Token");
String username = loginParam.getUsername();
String password = loginParam.getPassword();
ManagerInfo user = managerInfoService.findByUsername(username);
if (user.getPassword().equals(password)) {
return new BaseResponse<>(true, "Login success", JWTUtil.sign(username, password));
} else {
throw new UnauthorizedException();
}
}
@GetMapping(path = "/401")
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ApiIgnore
public BaseResponse unauthorized() {
return new BaseResponse<>(false, "Unauthorized", null);
}
}

View File

@ -0,0 +1,52 @@
package com.enzhico.jwt.api;
import com.enzhico.jwt.api.model.BaseResponse;
import com.enzhico.jwt.api.model.UnbindParam;
import com.enzhico.jwt.service.ApiService;
import io.swagger.annotations.*;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 通知接口类
*/
@Api(value = "通知接口类", tags = "通知", description = "服务器给相应客户端推送通知")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "请求已完成"),
@ApiResponse(code = 201, message = "资源成功被创建"),
@ApiResponse(code = 400, message = "请求中有语法问题,或不能满足请求"),
@ApiResponse(code = 401, message = "未授权客户机访问数据"),
@ApiResponse(code = 403, message = "服务器接受请求,但是拒绝处理"),
@ApiResponse(code = 404, message = "服务器找不到给定的资源;文档不存在"),
@ApiResponse(code = 500, message = "服务器出现异常")}
)
@RestController
@RequestMapping(value = "/notify")
public class NotifyController {
@Resource
private ApiService apiService;
private static final Logger _logger = LoggerFactory.getLogger(NotifyController.class);
@ApiOperation(value = "解绑通知接口", notes = "后台管理员解除网点绑定后需调用此接口通知相应的POS机", produces = "application/json")
@PostMapping("/unbind")
@RequiresUser
public BaseResponse unbind(@RequestHeader(name="Content-Type", defaultValue = "application/json") String contentType,
@RequestHeader(name="Authorization", defaultValue="token") String token,
@RequestBody UnbindParam unbindParam) {
_logger.info("解绑通知接口start");
String imei = unbindParam.getImei();
String location = unbindParam.getLocation();
String errMsg = apiService.sendUnbind(imei, location);
if (errMsg != null) {
return new BaseResponse<>(false, errMsg, null);
}
return new BaseResponse<>(true, "解绑通知发送成功", null);
}
}

View File

@ -0,0 +1,285 @@
package com.enzhico.jwt.api;
import com.enzhico.jwt.api.model.*;
import com.enzhico.jwt.common.dao.entity.Pos;
import com.enzhico.jwt.common.dao.entity.Project;
import com.enzhico.jwt.service.ApiService;
import com.enzhico.jwt.service.ManagerInfoService;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.Date;
/**
* 机具管理API接口类
*/
@Api(value = "机具管理业务接口类", tags = "机具管理", description = "机具管理业务接口类")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "请求已完成"),
@ApiResponse(code = 201, message = "资源成功被创建"),
@ApiResponse(code = 400, message = "请求中有语法问题,或不能满足请求"),
@ApiResponse(code = 401, message = "未授权客户机访问数据"),
@ApiResponse(code = 403, message = "服务器接受请求,但是拒绝处理"),
@ApiResponse(code = 404, message = "服务器找不到给定的资源;文档不存在"),
@ApiResponse(code = 500, message = "服务器出现异常")}
)
@RestController
@RequestMapping(value = "/api/v1")
public class PublicController {
@Resource
private ApiService apiService;
@Resource
private ManagerInfoService managerInfoService;
private static final Logger _logger = LoggerFactory.getLogger(PublicController.class);
/**
* 入网绑定查询接口
*
* @return 是否入网
*/
@ApiOperation(value = "入网绑定查询接口", notes = "根据IMEI码来查询该POS机是否入网并绑定了网点<br/>每次打开APP的时候需要调用这个接口来进行检查<br/>如果入网并且绑定了网点才能打开APP否则必须调用入网或绑定网点接口成功后才能继续下一步", produces = "application/json")
@ApiImplicitParam(name = "imei", value = "IMEI码", required = true, dataType = "String", paramType = "query", defaultValue = "1234555SHA")
@RequestMapping(value = "/join", method = RequestMethod.GET)
@RequiresUser
public JoinBindResponse join(@RequestHeader(name="Accept", defaultValue = "application/json", required = false) String accept,
@RequestHeader(name="Authorization", defaultValue="token") String token,
@RequestParam("imei") String imei) {
_logger.info("入网查询接口 start....");
JoinBindResponse result = new JoinBindResponse();
int posCount = apiService.selectCount(imei);
if (posCount > 0) {
// 如果入网了再去查询是否绑定了网点
int bindCount = apiService.selectBindCount(imei);
Pos pos = apiService.selectByImei(imei);
result.setPosState(pos.getPosState());
if (bindCount == 0) {
result.setSuccess(false);
result.setCode(2);
result.setMsg("已入网但尚未绑定网点");
} else {
result.setSuccess(true);
result.setCode(1);
result.setMsg("已入网并绑定了网点");
}
} else {
result.setSuccess(false);
result.setCode(3);
result.setMsg("未入网");
}
return result;
}
/**
* 请求入网接口
*
* @return 处理结果
*/
@ApiOperation(value = "请求入网接口", notes = "通过收集POS硬件信息请求入网另外还必须传入网点名称", produces = "application/json")
@RequestMapping(value = "/join", method = RequestMethod.POST)
@RequiresUser
public ResponseEntity<BaseResponse> doJoin(@RequestHeader(name="Content-Type", defaultValue = "application/json") String contentType,
@RequestHeader(name="Authorization", defaultValue="token") String token,
@RequestBody PosParam posParam) {
_logger.info("请求入网接口 start....");
BaseResponse result = new BaseResponse();
// imei码约束检查
if (StringUtils.isEmpty(posParam.getImei()) || posParam.getImei().length() > 32) {
result.setSuccess(false);
result.setMsg("IMEI码长度不是1-32位入网失败。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
// 序列号SN约束检查
if (StringUtils.isEmpty(posParam.getSn()) || posParam.getSn().length() > 64) {
result.setSuccess(false);
result.setMsg("序列号长度不是1-64位入网失败。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
// 机具型号约束检查
if (StringUtils.isEmpty(posParam.getSeries()) || posParam.getSeries().length() > 32) {
result.setSuccess(false);
result.setMsg("机具型号不是1-32位入网失败。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
// Android版本约束检查
if (StringUtils.isEmpty(posParam.getAndroidVersion()) || posParam.getAndroidVersion().length() > 32) {
result.setSuccess(false);
result.setMsg("Android版本号不是1-32位入网失败。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
// 版本号约束检查
if (StringUtils.isEmpty(posParam.getVersion()) || posParam.getVersion().length() > 32) {
result.setSuccess(false);
result.setMsg("版本号不是1-32位入网失败。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
// 归属网点约束检查
if (StringUtils.isEmpty(posParam.getLocation()) || posParam.getLocation().length() > 64) {
result.setSuccess(false);
result.setMsg("归属网点不是1-64位入网失败。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
// 产权方约束检查
if (StringUtils.isEmpty(posParam.getOwner()) || posParam.getOwner().length() > 64) {
result.setSuccess(false);
result.setMsg("产权方不是1-64位入网失败。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
// 应用ID约束检查
if (StringUtils.isEmpty(posParam.getApplicationId()) || posParam.getApplicationId().length() > 64) {
result.setSuccess(false);
result.setMsg("应用ID不是1-64位入网失败。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
// 备注约束检查
if (StringUtils.isNotEmpty(posParam.getTips()) && posParam.getTips().length() > 255) {
result.setSuccess(false);
result.setMsg("备注超过255个字符入网失败。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
Pos pos = new Pos();
Date now = new Date();
pos.setJointime(now);
pos.setBindtime(now);
BeanUtils.copyProperties(posParam, pos);
// 根据applicationId设置归属项目ID
Project project = apiService.selectProjectByApplicationId(posParam.getApplicationId());
if (project == null) {
result.setSuccess(false);
result.setMsg("Application Id不正确入网失败。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
// 重复检查
int posCount = apiService.selectCount(posParam.getImei());
if (posCount > 0) {
result.setSuccess(false);
result.setMsg("入网失败,该机具之前已经入网了。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
// 插入一条新纪录
pos.setProjectId(project.getId());
int insert = apiService.insertPos(pos);
if (insert > 0) {
result.setSuccess(true);
result.setMsg("入网成功");
return new ResponseEntity<>(result, HttpStatus.CREATED);
} else {
result.setSuccess(false);
result.setMsg("入网失败,请联系管理员。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
}
/**
* 请求绑定网点接口
*
* @return 处理结果
*/
@ApiOperation(value = "请求绑定网点接口", notes = "POS机重新绑定新的网点", produces = "application/json")
@RequestMapping(value = "/bind", method = RequestMethod.POST)
// @RequiresPermissions(logical = Logical.AND, value = {"view", "edit"})
@RequiresUser
public ResponseEntity<BaseResponse> doBind(@RequestHeader(name="Content-Type", defaultValue = "application/json") String contentType,
@RequestHeader(name="Authorization", defaultValue="token") String token,
@RequestBody BindParam bindParam) {
_logger.info("请求绑定网点接口 start....");
BaseResponse result = new BaseResponse();
// imei码约束检查
if (StringUtils.isEmpty(bindParam.getImei()) || bindParam.getImei().length() > 32) {
result.setSuccess(false);
result.setMsg("IMEI码长度不是1-32位绑定网点失败。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
// 归属网点约束检查
if (StringUtils.isEmpty(bindParam.getLocation()) || bindParam.getLocation().length() > 64) {
result.setSuccess(false);
result.setMsg("归属网点不是1-64位绑定网点失败。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
Pos pos = apiService.selectByImei(bindParam.getImei());
if (pos == null) {
result.setSuccess(false);
result.setMsg("该POS机尚未入网。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
Pos pos2 = apiService.selectBindByImei(bindParam.getImei());
if (pos2 != null) {
result.setSuccess(false);
result.setMsg("该POS机已经绑定了网点请先解绑。");
return new ResponseEntity<>(result, HttpStatus.OK);
}
pos.setLocation(bindParam.getLocation());
pos.setUpdatedTime(new Date());
apiService.bindLocation(pos);
result.setSuccess(true);
result.setMsg("绑定网点成功");
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* 报告位置接口
*
* @return 报告结果
*/
@ApiOperation(value = "报告位置接口", notes = "终端设备定时报告位置信息", produces = "application/json")
@RequestMapping(value = "/report", method = RequestMethod.POST)
@RequiresUser
public BaseResponse report(@RequestHeader(name="Content-Type", defaultValue = "application/json") String contentType,
@RequestHeader(name="Authorization", defaultValue="token") String token,
@RequestBody ReportParam param) {
_logger.info("定时报告接口 start....");
BaseResponse result = new BaseResponse();
// IMEI码约束检查
if (StringUtils.isEmpty(param.getImei()) || param.getImei().length() > 32) {
result.setSuccess(false);
result.setMsg("IMEI码不是1-32位心跳报告失败。");
return result;
}
// 地址约束检查
if (StringUtils.isEmpty(param.getLocation()) || param.getLocation().length() > 255) {
result.setSuccess(false);
result.setMsg("地址不是1-255位心跳报告失败。");
return result;
}
int r = apiService.report(param);
if (r > 0) {
result.setSuccess(true);
result.setMsg("心跳报告成功");
} else {
result.setSuccess(false);
result.setMsg("该POS机还没有入网心跳报告失败。");
}
return result;
}
/**
* 版本检查接口
*
* @return 版本检查结果
*/
@ApiOperation(value = "APP版本更新检查", notes = "APP版本更新检查", produces = "application/json")
@RequestMapping(value = "/version", method = RequestMethod.POST)
@RequiresUser
public VersionResult version(@RequestHeader(name="Content-Type", defaultValue = "application/json") String contentType,
@RequestHeader(name="Authorization", defaultValue="token") String token,
@RequestBody VersionParam param) {
_logger.info("版本检查接口 start....");
return apiService.selectPublishCount(param);
}
}

View File

@ -0,0 +1,68 @@
package com.enzhico.jwt.api.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import springfox.documentation.annotations.ApiIgnore;
/**
* API接口的基础返回类
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/7
*/
@ApiModel(value = "BaseResponse", description = "API接口的返回对象")
public class BaseResponse<T> {
/**
* 是否成功
*/
@ApiModelProperty(value = "是否成功", name = "success", example = "true", required = true)
private boolean success;
/**
* 说明
*/
@ApiModelProperty(value = "返回的详细说明", name = "msg", example = "成功")
private String msg;
/**
* 返回数据
*/
@ApiModelProperty(value = "返回的数据", name = "data")
private T data;
public BaseResponse() {
}
public BaseResponse(boolean success, String msg, T data) {
this.success = success;
this.msg = msg;
this.data = data;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}

View File

@ -0,0 +1,41 @@
package com.enzhico.jwt.api.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* POS绑定网点参数
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/7
*/
@ApiModel(value = "POS绑定网点参数", description = "POSPOS绑定网点请求时候需要传入的参数")
public class BindParam {
/**
* 机具IMEI码
*/
@ApiModelProperty(value = "IMEI码长度1-32位", name = "imei", dataType = "String", example = "2324DEEFAXX122", required = true)
private String imei;
/**
* 归属网点
*/
@ApiModelProperty(value = "归属网点长度1-64位", name = "location", dataType = "String", example = "昆明市公安局交通警察支队车辆管理所", required = true)
private String location;
public String getImei() {
return imei;
}
public void setImei(String imei) {
this.imei = imei;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}

View File

@ -0,0 +1,42 @@
package com.enzhico.jwt.api.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* 入网绑定返回
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/16
*/
@ApiModel(value = "入网绑定返回信息", description = "入网绑定的返回对象")
public class JoinBindResponse<T> extends BaseResponse<T> {
/**
* 返回码 1:已入网并绑定了网点 2:已入网但尚未绑定网点 3:未入网
*/
@ApiModelProperty(value = "返回码 1:已入网并绑定了网点 2:已入网但尚未绑定网点 3:未入网", name = "code", example = "1", required = true)
private int code;
/**
* 机具状态: 1:正常 2:故障 3:维修中(返厂) 4:已禁用(丢失) 5:已停用(回收)
*/
@ApiModelProperty(value = "机具状态 1:正常 2:故障 3:维修中(返厂) 4:已禁用(丢失) 5:已停用(回收)", name = "posState", example = "1", required = true)
private Integer posState;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public Integer getPosState() {
return posState;
}
public void setPosState(Integer posState) {
this.posState = posState;
}
}

View File

@ -0,0 +1,67 @@
package com.enzhico.jwt.api.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* 登录认证接口参数
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/9
*/
@ApiModel(value = "登录认证接口参数", description = "登录认证接口参数")
public class LoginParam {
/**
* 用户名
*/
@ApiModelProperty(value = "用户名", name = "username", example = "admin", required = true)
private String username;
/**
* 密码
*/
@ApiModelProperty(value = "密码", name = "password", example = "123456", required = true)
private String password;
/**
* Application ID
*/
@ApiModelProperty(value = "Application ID", name = "appid", example = "com.enzhico.xzpay", required = false)
private String appid;
/**
* IMEI码
*/
@ApiModelProperty(value = "IMEI码", name = "imei", example = "TUYIUOIU234234YUII", required = false)
private String imei;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getImei() {
return imei;
}
public void setImei(String imei) {
this.imei = imei;
}
}

View File

@ -0,0 +1,133 @@
package com.enzhico.jwt.api.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* POS入网参数
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/7
*/
@ApiModel(value = "POS入网参数", description = "POS入网请求时候需要传入的参数")
public class PosParam {
/**
* 机具IMEI码
*/
@ApiModelProperty(value = "IMEI码长度1-32位", name = "imei", dataType = "String", example = "2324DEEFAXX122", required = true)
private String imei;
/**
* 序列号(SN)
*/
@ApiModelProperty(value = "序列号SN长度1-64位", name = "sn", dataType = "String", example = "ssssssnnnn", required = true)
private String sn;
/**
* 机具型号
*/
@ApiModelProperty(value = "机具型号长度1-32位", name = "series", dataType = "String", example = "APOS A8", required = true)
private String series;
/**
* Android版本
*/
@ApiModelProperty(value = "Android版本长度1-32位", name = "androidVersion", dataType = "String", example = "6.2.0", required = true)
private String androidVersion;
/**
* 版本号
*/
@ApiModelProperty(value = "版本号长度1-32位", name = "version", dataType = "String", example = "B0182_C2BOM_V1.1.4_20171213/4.0.28", required = true)
private String version;
/**
* 归属网点
*/
@ApiModelProperty(value = "归属网点长度1-64位", name = "location", dataType = "String", example = "昆明市公安局交通警察支队车辆管理所", required = true)
private String location;
/**
* 产权方
*/
@ApiModelProperty(value = "机具产权方长度1-64位", name = "owner", dataType = "String", example = "招商银行昆明分行", required = true)
private String owner;
/**
* 备注
*/
@ApiModelProperty(value = "备注说明长度0-255位", name = "tips", dataType = "String", example = "备注说明")
private String tips;
/**
* 应用ID
*/
@ApiModelProperty(value = "APP应用ID长度1-64位每个APP都有唯一的Application Id并且这个应用ID必须已经存在于系统之中",
name = "applicationId", dataType = "String", example = "com.enzhico.xzpay", required = true)
private String applicationId;
public String getImei() {
return imei;
}
public void setImei(String imei) {
this.imei = imei;
}
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public String getSeries() {
return series;
}
public void setSeries(String series) {
this.series = series;
}
public String getAndroidVersion() {
return androidVersion;
}
public void setAndroidVersion(String androidVersion) {
this.androidVersion = androidVersion;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getTips() {
return tips;
}
public void setTips(String tips) {
this.tips = tips;
}
public String getApplicationId() {
return applicationId;
}
public void setApplicationId(String applicationId) {
this.applicationId = applicationId;
}
}

View File

@ -0,0 +1,41 @@
package com.enzhico.jwt.api.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* 报告参数
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/7
*/
@ApiModel(value = "报告参数", description = "报告参数")
public class ReportParam {
/**
* IMEI码
*/
@ApiModelProperty(value = "IMEI码长度1-32位", name = "imei", example = "2324DEEFAXX122", required = true)
private String imei;
/**
* 位置
*/
@ApiModelProperty(value = "位置长度1-255位", name = "location", example = "广东省广州市天河区五山路321号", required = true)
private String location;
public String getImei() {
return imei;
}
public void setImei(String imei) {
this.imei = imei;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}

View File

@ -0,0 +1,41 @@
package com.enzhico.jwt.api.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* 解绑通知参数
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/9
*/
@ApiModel(value = "解绑通知参数", description = "解绑通知参数")
public class UnbindParam {
/**
* IMEI码
*/
@ApiModelProperty(value = "IMEI码", name = "imei", example = "TUYIUOIU234234YUII")
private String imei;
/**
* 网点
*/
@ApiModelProperty(value = "网点", name = "location", example = "广州市天河区交警7区")
private String location;
public String getImei() {
return imei;
}
public void setImei(String imei) {
this.imei = imei;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}

View File

@ -0,0 +1,54 @@
package com.enzhico.jwt.api.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* APP版本检查接口参数
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/9
*/
@ApiModel(value = "APP版本检查参数", description = "APP版本检查参数")
public class VersionParam {
/**
* 机具IMEI码
*/
@ApiModelProperty(value = "IMEI码", name = "imei", example = "2324DEEFAXX122", required = true)
private String imei;
/**
* 应用ID
*/
@ApiModelProperty(value = "APP应用ID每个APP都有唯一的Application Id", name = "applicationId", example = "com.enzhico.xzpay", required = true)
private String applicationId;
/**
* 当前版本号
*/
@ApiModelProperty(value = "APP的当前版本号", name = "version", example = "1.2.0", required = true)
private String version;
public String getApplicationId() {
return applicationId;
}
public void setApplicationId(String applicationId) {
this.applicationId = applicationId;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getImei() {
return imei;
}
public void setImei(String imei) {
this.imei = imei;
}
}

View File

@ -0,0 +1,96 @@
package com.enzhico.jwt.api.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
/**
* 版本检查结果
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/9
*/
@ApiModel(value = "APP版本检查结果", description = "APP版本检查结果")
public class VersionResult {
/**
* 是否发现新版本
*/
@ApiModelProperty(value = "是否发现新版本(true:发现新版本false:没有发现新版本)", name = "findNew", example = "true", required = true)
private boolean findNew;
/**
* APP名称
*/
@ApiModelProperty(value = "APP名称", name = "appName", example = "行政收费")
private String appName;
/**
* 新版本号
*/
@ApiModelProperty(value = "新版本号", name = "version", example = "v1.3.8")
private String version;
/**
* 新版本说明
*/
@ApiModelProperty(value = "新版本说明", name = "tips", example = "增加人脸识别功能")
private String tips;
/**
* 新版本发布时间
*/
@ApiModelProperty(value = "新版本发布时间", name = "publishtime", example = "2017-12-24 12:32:19")
private Date publishtime;
/**
* 新版本下载地址
*/
@ApiModelProperty(value = "新版本下载地址", name = "downloadUrl", example = "http://enzhico.net/files/行政收费_1.3.0.apk")
private String downloadUrl;
public boolean isFindNew() {
return findNew;
}
public void setFindNew(boolean findNew) {
this.findNew = findNew;
}
public String getDownloadUrl() {
return downloadUrl;
}
public void setDownloadUrl(String downloadUrl) {
this.downloadUrl = downloadUrl;
}
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getTips() {
return tips;
}
public void setTips(String tips) {
this.tips = tips;
}
public Date getPublishtime() {
return publishtime;
}
public void setPublishtime(Date publishtime) {
this.publishtime = publishtime;
}
}

View File

@ -0,0 +1,34 @@
package com.enzhico.jwt.common;
import com.corundumstudio.socketio.SocketIOServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* SpringBoot启动之后执行
*
* @author XiongNeng
* @version 1.0
* @since 2017/7/31
*/
@Component
@Order(1)
public class ServerRunner implements CommandLineRunner {
private final SocketIOServer server;
private static final Logger logger = LoggerFactory.getLogger(ServerRunner.class);
@Autowired
public ServerRunner(SocketIOServer server) {
this.server = server;
}
@Override
public void run(String... args) {
logger.info("ServerRunner 开始启动啦...");
server.start();
}
}

View File

@ -0,0 +1,37 @@
package com.enzhico.jwt.common.constant;
import java.util.ArrayList;
import java.util.List;
/**
* 常量列表
*
* @author XiongNeng
* @version 1.0
* @since 2018/01/07
*/
public class ConstantsList {
// 应收款项列表
public static final List<String> INCOME_TYPE_LIST = new ArrayList<String>() {{
add("租金");
add("市场管理费");
add("物业管理费");
add("其他");
}};
// 市场列表
public static final List<String> MARKET_LIST = new ArrayList<String>() {{
add("一期市场");
add("二期市场");
add("三期市场");
}};
// 业态
public static final List<String> BUSINESS_LIST = new ArrayList<String>() {{
add("男装");
add("女装");
add("玩具");
add("餐饮");
add("家具");
}};
}

View File

@ -0,0 +1,80 @@
package com.enzhico.jwt.common.constant;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
/**
* 表常量字典
*
* @author XiongNeng
* @version 1.0
* @since 2018/01/07
*/
public class DictMap {
/**
* 后台管理用户表 - 状态(1:正常 2:禁用)
*/
public static final String KEY_USER_STATUS = "t_manager.status";
/**
* POS机表 - 机具状态(1:正常 2:故障 3:维修中(返厂) 4:已禁用(丢失) 5:已停用(回收))
*/
public static final String KEY_POS_POS_STATUS = "t_pos.pos_state";
/**
* POS机监控表 - 在线状态(1:在线 2:离线)
*/
public static final String KEY_POS_MONITOR_STATUS = "t_pos_monitor.online_state";
/**
* APP表 - 发布范围(1:全网发布 2:灰度发布)
*/
public static final String KEY_APP_PUBLISH_RANGE = "t_app.publish_range";
/**
* 内部用ClassName + FieldName为key
*/
private static final Map<String, TreeMap<Integer, String>> _imap = new HashMap<>();
static {
_imap.put(KEY_USER_STATUS, new TreeMap<Integer, String>() {{
put(1, "正常");
put(2, "禁用");
}});
_imap.put(KEY_POS_POS_STATUS, new TreeMap<Integer, String>() {{
put(1, "正常");
put(2, "故障");
put(3, "维修中(返厂)");
put(4, "已禁用(丢失)");
put(5, "已停用(回收)");
}});
_imap.put(KEY_POS_MONITOR_STATUS, new TreeMap<Integer, String>() {{
put(1, "在线");
put(2, "离线");
}});
_imap.put(KEY_APP_PUBLISH_RANGE, new TreeMap<Integer, String>() {{
put(1, "全网发布");
put(2, "灰度发布");
}});
}
/**
* 根据字典类型key获取某个字典Map
*
* @param type 常量类型
* @return 字典Map
*/
public static TreeMap<Integer, String> map(String type) {
return _imap.get(type);
}
/**
* 根据字典类型和数字获取对应的字符串
*
* @param type 字典类型
* @param key 数字
* @return 对应的字符串
*/
public static String value(String type, Integer key) {
return key != null ? map(type).get(key) : null;
}
}

View File

@ -0,0 +1,273 @@
package com.enzhico.jwt.common.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.activerecord.Model;
import java.io.Serializable;
/**
* APP表
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
@TableName(value = "t_app")
public class App extends Model<App> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 应用编号
*/
private String applicationId;
/**
* 应用名称
*/
private String name;
/**
* 版本号
*/
private String version;
/**
* 版本说明
*/
private String tips;
/**
* 归属项目ID
*/
private Integer projectId;
/**
* 发布时间
*/
private Date publishtime;
/**
* 发布范围 1:全网发布 2:灰度发布
*/
private Integer publishRange;
/**
* 操作者ID
*/
private Integer operatorId;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 获取 主键ID.
*
* @return 主键ID.
*/
public Integer getId() {
return id;
}
/**
* 设置 主键ID.
*
* @param id 主键ID.
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取 应用编号.
*
* @return 应用编号.
*/
public String getApplicationId() {
return applicationId;
}
/**
* 设置 应用编号.
*
* @param applicationId 应用编号.
*/
public void setApplicationId(String applicationId) {
this.applicationId = applicationId;
}
/**
* 获取 应用名称.
*
* @return 应用名称.
*/
public String getName() {
return name;
}
/**
* 设置 应用名称.
*
* @param name 应用名称.
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取 版本号.
*
* @return 版本号.
*/
public String getVersion() {
return version;
}
/**
* 设置 版本号.
*
* @param version 版本号.
*/
public void setVersion(String version) {
this.version = version;
}
/**
* 获取 版本说明.
*
* @return 版本说明.
*/
public String getTips() {
return tips;
}
/**
* 设置 版本说明.
*
* @param tips 版本说明.
*/
public void setTips(String tips) {
this.tips = tips;
}
/**
* 获取 归属项目ID.
*
* @return 归属项目ID.
*/
public Integer getProjectId() {
return projectId;
}
/**
* 设置 归属项目ID.
*
* @param projectId 归属项目ID.
*/
public void setProjectId(Integer projectId) {
this.projectId = projectId;
}
/**
* 获取 发布时间.
*
* @return 发布时间.
*/
public Date getPublishtime() {
return publishtime;
}
/**
* 设置 发布时间.
*
* @param publishtime 发布时间.
*/
public void setPublishtime(Date publishtime) {
this.publishtime = publishtime;
}
/**
* 获取 发布范围 1:全网发布 2:灰度发布.
*
* @return 发布范围 1:全网发布 2:灰度发布.
*/
public Integer getPublishRange() {
return publishRange;
}
/**
* 设置 发布范围 1:全网发布 2:灰度发布.
*
* @param publishRange 发布范围 1:全网发布 2:灰度发布.
*/
public void setPublishRange(Integer publishRange) {
this.publishRange = publishRange;
}
/**
* 获取 操作者ID.
*
* @return 操作者ID.
*/
public Integer getOperatorId() {
return operatorId;
}
/**
* 设置 操作者ID.
*
* @param operatorId 操作者ID.
*/
public void setOperatorId(Integer operatorId) {
this.operatorId = operatorId;
}
/**
* 获取 创建时间.
*
* @return 创建时间.
*/
public Date getCreatedTime() {
return createdTime;
}
/**
* 设置 创建时间.
*
* @param createdTime 创建时间.
*/
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
/**
* 获取 更新时间.
*
* @return 更新时间.
*/
public Date getUpdatedTime() {
return updatedTime;
}
/**
* 设置 更新时间.
*
* @param updatedTime 更新时间.
*/
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
@Override
protected Serializable pkVal() {
return this.id;
}
}

View File

@ -0,0 +1,141 @@
package com.enzhico.jwt.common.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.activerecord.Model;
import java.io.Serializable;
/**
* APP发布表
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
@TableName(value = "t_app_publish")
public class AppPublish extends Model<AppPublish> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* APP主键
*/
private Integer appId;
/**
* POS主键
*/
private Integer posId;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 获取 主键ID.
*
* @return 主键ID.
*/
public Integer getId() {
return id;
}
/**
* 设置 主键ID.
*
* @param id 主键ID.
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取 APP主键.
*
* @return APP主键.
*/
public Integer getAppId() {
return appId;
}
/**
* 设置 APP主键.
*
* @param appId APP主键.
*/
public void setAppId(Integer appId) {
this.appId = appId;
}
/**
* 获取 POS主键.
*
* @return POS主键.
*/
public Integer getPosId() {
return posId;
}
/**
* 设置 POS主键.
*
* @param posId POS主键.
*/
public void setPosId(Integer posId) {
this.posId = posId;
}
/**
* 获取 创建时间.
*
* @return 创建时间.
*/
public Date getCreatedTime() {
return createdTime;
}
/**
* 设置 创建时间.
*
* @param createdTime 创建时间.
*/
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
/**
* 获取 更新时间.
*
* @return 更新时间.
*/
public Date getUpdatedTime() {
return updatedTime;
}
/**
* 设置 更新时间.
*
* @param updatedTime 更新时间.
*/
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
@Override
protected Serializable pkVal() {
return this.id;
}
}

View File

@ -0,0 +1,251 @@
package com.enzhico.jwt.common.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.activerecord.Model;
import java.io.Serializable;
/**
* 后台管理用户表
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
@TableName(value = "t_manager")
public class Manager extends Model<Manager> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 账号
*/
private String username;
/**
* 名字
*/
private String name;
/**
* 密码
*/
private String password;
/**
* md5密码盐
*/
private String salt;
/**
* 联系电话
*/
private String phone;
/**
* 备注
*/
private String tips;
/**
* 状态 1:正常 2:禁用
*/
private Integer state;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 获取 主键ID.
*
* @return 主键ID.
*/
public Integer getId() {
return id;
}
/**
* 设置 主键ID.
*
* @param id 主键ID.
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取 账号.
*
* @return 账号.
*/
public String getUsername() {
return username;
}
/**
* 设置 账号.
*
* @param username 账号.
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 获取 名字.
*
* @return 名字.
*/
public String getName() {
return name;
}
/**
* 设置 名字.
*
* @param name 名字.
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取 密码.
*
* @return 密码.
*/
public String getPassword() {
return password;
}
/**
* 设置 密码.
*
* @param password 密码.
*/
public void setPassword(String password) {
this.password = password;
}
/**
* 获取 md5密码盐.
*
* @return md5密码盐.
*/
public String getSalt() {
return salt;
}
/**
* 设置 md5密码盐.
*
* @param salt md5密码盐.
*/
public void setSalt(String salt) {
this.salt = salt;
}
/**
* 获取 联系电话.
*
* @return 联系电话.
*/
public String getPhone() {
return phone;
}
/**
* 设置 联系电话.
*
* @param phone 联系电话.
*/
public void setPhone(String phone) {
this.phone = phone;
}
/**
* 获取 备注.
*
* @return 备注.
*/
public String getTips() {
return tips;
}
/**
* 设置 备注.
*
* @param tips 备注.
*/
public void setTips(String tips) {
this.tips = tips;
}
/**
* 获取 状态 1:正常 2:禁用.
*
* @return 状态 1:正常 2:禁用.
*/
public Integer getState() {
return state;
}
/**
* 设置 状态 1:正常 2:禁用.
*
* @param state 状态 1:正常 2:禁用.
*/
public void setState(Integer state) {
this.state = state;
}
/**
* 获取 创建时间.
*
* @return 创建时间.
*/
public Date getCreatedTime() {
return createdTime;
}
/**
* 设置 创建时间.
*
* @param createdTime 创建时间.
*/
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
/**
* 获取 更新时间.
*
* @return 更新时间.
*/
public Date getUpdatedTime() {
return updatedTime;
}
/**
* 设置 更新时间.
*
* @param updatedTime 更新时间.
*/
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
@Override
protected Serializable pkVal() {
return this.id;
}
}

View File

@ -0,0 +1,141 @@
package com.enzhico.jwt.common.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.activerecord.Model;
import java.io.Serializable;
/**
* 用户角色关联表
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
@TableName(value = "t_manager_role")
public class ManagerRole extends Model<ManagerRole> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 管理用户ID
*/
private Integer managerId;
/**
* 角色ID
*/
private Integer roleId;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 获取 主键ID.
*
* @return 主键ID.
*/
public Integer getId() {
return id;
}
/**
* 设置 主键ID.
*
* @param id 主键ID.
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取 管理用户ID.
*
* @return 管理用户ID.
*/
public Integer getManagerId() {
return managerId;
}
/**
* 设置 管理用户ID.
*
* @param managerId 管理用户ID.
*/
public void setManagerId(Integer managerId) {
this.managerId = managerId;
}
/**
* 获取 角色ID.
*
* @return 角色ID.
*/
public Integer getRoleId() {
return roleId;
}
/**
* 设置 角色ID.
*
* @param roleId 角色ID.
*/
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
/**
* 获取 创建时间.
*
* @return 创建时间.
*/
public Date getCreatedTime() {
return createdTime;
}
/**
* 设置 创建时间.
*
* @param createdTime 创建时间.
*/
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
/**
* 获取 更新时间.
*
* @return 更新时间.
*/
public Date getUpdatedTime() {
return updatedTime;
}
/**
* 设置 更新时间.
*
* @param updatedTime 更新时间.
*/
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
@Override
protected Serializable pkVal() {
return this.id;
}
}

View File

@ -0,0 +1,207 @@
package com.enzhico.jwt.common.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.activerecord.Model;
import java.io.Serializable;
/**
* 操作日志表
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
@TableName(value = "t_operation_log")
public class OperationLog extends Model<OperationLog> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 操作者ID
*/
private Integer operatorId;
/**
* 操作对象ID
*/
private Integer targetId;
/**
* 操作对象名称
*/
private String targetName;
/**
* 操作类型
*/
private String operateType;
/**
* 备注
*/
private String tips;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 获取 主键ID.
*
* @return 主键ID.
*/
public Integer getId() {
return id;
}
/**
* 设置 主键ID.
*
* @param id 主键ID.
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取 操作者ID.
*
* @return 操作者ID.
*/
public Integer getOperatorId() {
return operatorId;
}
/**
* 设置 操作者ID.
*
* @param operatorId 操作者ID.
*/
public void setOperatorId(Integer operatorId) {
this.operatorId = operatorId;
}
/**
* 获取 操作对象ID.
*
* @return 操作对象ID.
*/
public Integer getTargetId() {
return targetId;
}
/**
* 设置 操作对象ID.
*
* @param targetId 操作对象ID.
*/
public void setTargetId(Integer targetId) {
this.targetId = targetId;
}
/**
* 获取 操作对象名称.
*
* @return 操作对象名称.
*/
public String getTargetName() {
return targetName;
}
/**
* 设置 操作对象名称.
*
* @param targetName 操作对象名称.
*/
public void setTargetName(String targetName) {
this.targetName = targetName;
}
/**
* 获取 操作类型.
*
* @return 操作类型.
*/
public String getOperateType() {
return operateType;
}
/**
* 设置 操作类型.
*
* @param operateType 操作类型.
*/
public void setOperateType(String operateType) {
this.operateType = operateType;
}
/**
* 获取 备注.
*
* @return 备注.
*/
public String getTips() {
return tips;
}
/**
* 设置 备注.
*
* @param tips 备注.
*/
public void setTips(String tips) {
this.tips = tips;
}
/**
* 获取 创建时间.
*
* @return 创建时间.
*/
public Date getCreatedTime() {
return createdTime;
}
/**
* 设置 创建时间.
*
* @param createdTime 创建时间.
*/
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
/**
* 获取 更新时间.
*
* @return 更新时间.
*/
public Date getUpdatedTime() {
return updatedTime;
}
/**
* 设置 更新时间.
*
* @param updatedTime 更新时间.
*/
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
@Override
protected Serializable pkVal() {
return this.id;
}
}

View File

@ -0,0 +1,141 @@
package com.enzhico.jwt.common.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.activerecord.Model;
import java.io.Serializable;
/**
* 权限表
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
@TableName(value = "t_permission")
public class Permission extends Model<Permission> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 权限名称
*/
private String permission;
/**
* 权限说明
*/
private String description;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 获取 主键ID.
*
* @return 主键ID.
*/
public Integer getId() {
return id;
}
/**
* 设置 主键ID.
*
* @param id 主键ID.
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取 权限名称.
*
* @return 权限名称.
*/
public String getPermission() {
return permission;
}
/**
* 设置 权限名称.
*
* @param permission 权限名称.
*/
public void setPermission(String permission) {
this.permission = permission;
}
/**
* 获取 权限说明.
*
* @return 权限说明.
*/
public String getDescription() {
return description;
}
/**
* 设置 权限说明.
*
* @param description 权限说明.
*/
public void setDescription(String description) {
this.description = description;
}
/**
* 获取 创建时间.
*
* @return 创建时间.
*/
public Date getCreatedTime() {
return createdTime;
}
/**
* 设置 创建时间.
*
* @param createdTime 创建时间.
*/
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
/**
* 获取 更新时间.
*
* @return 更新时间.
*/
public Date getUpdatedTime() {
return updatedTime;
}
/**
* 设置 更新时间.
*
* @param updatedTime 更新时间.
*/
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
@Override
protected Serializable pkVal() {
return this.id;
}
}

View File

@ -0,0 +1,361 @@
package com.enzhico.jwt.common.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.activerecord.Model;
import java.io.Serializable;
/**
* POS机表
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
@TableName(value = "t_pos")
public class Pos extends Model<Pos> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 机具IMEI码
*/
private String imei;
/**
* 序列号(SN)
*/
private String sn;
/**
* 机具型号
*/
private String series;
/**
* Android版本
*/
private String androidVersion;
/**
* 版本号
*/
private String version;
/**
* 归属网点
*/
private String location;
/**
* 归属项目ID
*/
private Integer projectId;
/**
* 入网时间
*/
private Date jointime;
/**
* 绑定时间
*/
private Date bindtime;
/**
* 产权方
*/
private String owner;
/**
* 备注
*/
private String tips;
/**
* 机具状态: 1:正常 2:故障 3:维修中(返厂) 4:已禁用(丢失) 5:已停用(回收)
*/
private Integer posState;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 获取 主键ID.
*
* @return 主键ID.
*/
public Integer getId() {
return id;
}
/**
* 设置 主键ID.
*
* @param id 主键ID.
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取 机具IMEI码.
*
* @return 机具IMEI码.
*/
public String getImei() {
return imei;
}
/**
* 设置 机具IMEI码.
*
* @param imei 机具IMEI码.
*/
public void setImei(String imei) {
this.imei = imei;
}
/**
* 获取 序列号(SN).
*
* @return 序列号(SN).
*/
public String getSn() {
return sn;
}
/**
* 设置 序列号(SN).
*
* @param sn 序列号(SN).
*/
public void setSn(String sn) {
this.sn = sn;
}
/**
* 获取 机具型号.
*
* @return 机具型号.
*/
public String getSeries() {
return series;
}
/**
* 设置 机具型号.
*
* @param series 机具型号.
*/
public void setSeries(String series) {
this.series = series;
}
/**
* 获取 Android版本.
*
* @return Android版本.
*/
public String getAndroidVersion() {
return androidVersion;
}
/**
* 设置 Android版本.
*
* @param androidVersion Android版本.
*/
public void setAndroidVersion(String androidVersion) {
this.androidVersion = androidVersion;
}
/**
* 获取 版本号.
*
* @return 版本号.
*/
public String getVersion() {
return version;
}
/**
* 设置 版本号.
*
* @param version 版本号.
*/
public void setVersion(String version) {
this.version = version;
}
/**
* 获取 归属网点.
*
* @return 归属网点.
*/
public String getLocation() {
return location;
}
/**
* 设置 归属网点.
*
* @param location 归属网点.
*/
public void setLocation(String location) {
this.location = location;
}
/**
* 获取 归属项目ID.
*
* @return 归属项目ID.
*/
public Integer getProjectId() {
return projectId;
}
/**
* 设置 归属项目ID.
*
* @param projectId 归属项目ID.
*/
public void setProjectId(Integer projectId) {
this.projectId = projectId;
}
/**
* 获取 入网时间.
*
* @return 入网时间.
*/
public Date getJointime() {
return jointime;
}
/**
* 设置 入网时间.
*
* @param jointime 入网时间.
*/
public void setJointime(Date jointime) {
this.jointime = jointime;
}
/**
* 获取 绑定时间.
*
* @return 绑定时间.
*/
public Date getBindtime() {
return bindtime;
}
/**
* 设置 绑定时间.
*
* @param bindtime 绑定时间.
*/
public void setBindtime(Date bindtime) {
this.bindtime = bindtime;
}
/**
* 获取 产权方.
*
* @return 产权方.
*/
public String getOwner() {
return owner;
}
/**
* 设置 产权方.
*
* @param owner 产权方.
*/
public void setOwner(String owner) {
this.owner = owner;
}
/**
* 获取 备注.
*
* @return 备注.
*/
public String getTips() {
return tips;
}
/**
* 设置 备注.
*
* @param tips 备注.
*/
public void setTips(String tips) {
this.tips = tips;
}
/**
* 获取 机具状态: 1:正常 2:故障 3:维修中(返厂) 4:已禁用(丢失) 5:已停用(回收).
*
* @return 机具状态: 1:正常 2:故障 3:维修中(返厂) 4:已禁用(丢失) 5:已停用(回收).
*/
public Integer getPosState() {
return posState;
}
/**
* 设置 机具状态: 1:正常 2:故障 3:维修中(返厂) 4:已禁用(丢失) 5:已停用(回收).
*
* @param posState 机具状态: 1:正常 2:故障 3:维修中(返厂) 4:已禁用(丢失) 5:已停用(回收).
*/
public void setPosState(Integer posState) {
this.posState = posState;
}
/**
* 获取 创建时间.
*
* @return 创建时间.
*/
public Date getCreatedTime() {
return createdTime;
}
/**
* 设置 创建时间.
*
* @param createdTime 创建时间.
*/
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
/**
* 获取 更新时间.
*
* @return 更新时间.
*/
public Date getUpdatedTime() {
return updatedTime;
}
/**
* 设置 更新时间.
*
* @param updatedTime 更新时间.
*/
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
@Override
protected Serializable pkVal() {
return this.id;
}
}

View File

@ -0,0 +1,185 @@
package com.enzhico.jwt.common.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.activerecord.Model;
import java.io.Serializable;
/**
* POS机历史归属表
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
@TableName(value = "t_pos_history")
public class PosHistory extends Model<PosHistory> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* POS机ID
*/
private Integer posId;
/**
* 归属网点
*/
private String location;
/**
* 绑定时间
*/
private Date bindtime;
/**
* 解绑时间
*/
private Date unbindtime;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 获取 主键ID.
*
* @return 主键ID.
*/
public Integer getId() {
return id;
}
/**
* 设置 主键ID.
*
* @param id 主键ID.
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取 POS机ID.
*
* @return POS机ID.
*/
public Integer getPosId() {
return posId;
}
/**
* 设置 POS机ID.
*
* @param posId POS机ID.
*/
public void setPosId(Integer posId) {
this.posId = posId;
}
/**
* 获取 归属网点.
*
* @return 归属网点.
*/
public String getLocation() {
return location;
}
/**
* 设置 归属网点.
*
* @param location 归属网点.
*/
public void setLocation(String location) {
this.location = location;
}
/**
* 获取 绑定时间.
*
* @return 绑定时间.
*/
public Date getBindtime() {
return bindtime;
}
/**
* 设置 绑定时间.
*
* @param bindtime 绑定时间.
*/
public void setBindtime(Date bindtime) {
this.bindtime = bindtime;
}
/**
* 获取 解绑时间.
*
* @return 解绑时间.
*/
public Date getUnbindtime() {
return unbindtime;
}
/**
* 设置 解绑时间.
*
* @param unbindtime 解绑时间.
*/
public void setUnbindtime(Date unbindtime) {
this.unbindtime = unbindtime;
}
/**
* 获取 创建时间.
*
* @return 创建时间.
*/
public Date getCreatedTime() {
return createdTime;
}
/**
* 设置 创建时间.
*
* @param createdTime 创建时间.
*/
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
/**
* 获取 更新时间.
*
* @return 更新时间.
*/
public Date getUpdatedTime() {
return updatedTime;
}
/**
* 设置 更新时间.
*
* @param updatedTime 更新时间.
*/
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
@Override
protected Serializable pkVal() {
return this.id;
}
}

View File

@ -0,0 +1,207 @@
package com.enzhico.jwt.common.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.activerecord.Model;
import java.io.Serializable;
/**
* POS机监控表
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
@TableName(value = "t_pos_monitor")
public class PosMonitor extends Model<PosMonitor> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* POS机ID
*/
private Integer posId;
/**
* Socket会话ID
*/
private String sessionId;
/**
* 最近一次报告时间
*/
private Date reportTime;
/**
* 最近一次报告地址
*/
private String reportLocation;
/**
* 在线状态: 1:在线 2:离线
*/
private Integer onlineState;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 获取 主键ID.
*
* @return 主键ID.
*/
public Integer getId() {
return id;
}
/**
* 设置 主键ID.
*
* @param id 主键ID.
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取 POS机ID.
*
* @return POS机ID.
*/
public Integer getPosId() {
return posId;
}
/**
* 设置 POS机ID.
*
* @param posId POS机ID.
*/
public void setPosId(Integer posId) {
this.posId = posId;
}
/**
* 获取 Socket会话ID.
*
* @return Socket会话ID.
*/
public String getSessionId() {
return sessionId;
}
/**
* 设置 Socket会话ID.
*
* @param sessionId Socket会话ID.
*/
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
/**
* 获取 最近一次报告时间.
*
* @return 最近一次报告时间.
*/
public Date getReportTime() {
return reportTime;
}
/**
* 设置 最近一次报告时间.
*
* @param reportTime 最近一次报告时间.
*/
public void setReportTime(Date reportTime) {
this.reportTime = reportTime;
}
/**
* 获取 最近一次报告地址.
*
* @return 最近一次报告地址.
*/
public String getReportLocation() {
return reportLocation;
}
/**
* 设置 最近一次报告地址.
*
* @param reportLocation 最近一次报告地址.
*/
public void setReportLocation(String reportLocation) {
this.reportLocation = reportLocation;
}
/**
* 获取 在线状态: 1:在线 2:离线.
*
* @return 在线状态: 1:在线 2:离线.
*/
public Integer getOnlineState() {
return onlineState;
}
/**
* 设置 在线状态: 1:在线 2:离线.
*
* @param onlineState 在线状态: 1:在线 2:离线.
*/
public void setOnlineState(Integer onlineState) {
this.onlineState = onlineState;
}
/**
* 获取 创建时间.
*
* @return 创建时间.
*/
public Date getCreatedTime() {
return createdTime;
}
/**
* 设置 创建时间.
*
* @param createdTime 创建时间.
*/
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
/**
* 获取 更新时间.
*
* @return 更新时间.
*/
public Date getUpdatedTime() {
return updatedTime;
}
/**
* 设置 更新时间.
*
* @param updatedTime 更新时间.
*/
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
@Override
protected Serializable pkVal() {
return this.id;
}
}

View File

@ -0,0 +1,163 @@
package com.enzhico.jwt.common.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.activerecord.Model;
import java.io.Serializable;
/**
* 项目表
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
@TableName(value = "t_project")
public class Project extends Model<Project> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 项目名称
*/
private String name;
/**
* 应用编号
*/
private String applicationId;
/**
* 项目图片
*/
private String icon;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 获取 主键ID.
*
* @return 主键ID.
*/
public Integer getId() {
return id;
}
/**
* 设置 主键ID.
*
* @param id 主键ID.
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取 项目名称.
*
* @return 项目名称.
*/
public String getName() {
return name;
}
/**
* 设置 项目名称.
*
* @param name 项目名称.
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取 应用编号.
*
* @return 应用编号.
*/
public String getApplicationId() {
return applicationId;
}
/**
* 设置 应用编号.
*
* @param applicationId 应用编号.
*/
public void setApplicationId(String applicationId) {
this.applicationId = applicationId;
}
/**
* 获取 项目图片.
*
* @return 项目图片.
*/
public String getIcon() {
return icon;
}
/**
* 设置 项目图片.
*
* @param icon 项目图片.
*/
public void setIcon(String icon) {
this.icon = icon;
}
/**
* 获取 创建时间.
*
* @return 创建时间.
*/
public Date getCreatedTime() {
return createdTime;
}
/**
* 设置 创建时间.
*
* @param createdTime 创建时间.
*/
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
/**
* 获取 更新时间.
*
* @return 更新时间.
*/
public Date getUpdatedTime() {
return updatedTime;
}
/**
* 设置 更新时间.
*
* @param updatedTime 更新时间.
*/
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
@Override
protected Serializable pkVal() {
return this.id;
}
}

View File

@ -0,0 +1,141 @@
package com.enzhico.jwt.common.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.activerecord.Model;
import java.io.Serializable;
/**
* 项目用户关联表
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
@TableName(value = "t_project_user")
public class ProjectUser extends Model<ProjectUser> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 用户ID
*/
private Integer userId;
/**
* 项目ID
*/
private Integer projectId;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 获取 主键ID.
*
* @return 主键ID.
*/
public Integer getId() {
return id;
}
/**
* 设置 主键ID.
*
* @param id 主键ID.
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取 用户ID.
*
* @return 用户ID.
*/
public Integer getUserId() {
return userId;
}
/**
* 设置 用户ID.
*
* @param userId 用户ID.
*/
public void setUserId(Integer userId) {
this.userId = userId;
}
/**
* 获取 项目ID.
*
* @return 项目ID.
*/
public Integer getProjectId() {
return projectId;
}
/**
* 设置 项目ID.
*
* @param projectId 项目ID.
*/
public void setProjectId(Integer projectId) {
this.projectId = projectId;
}
/**
* 获取 创建时间.
*
* @return 创建时间.
*/
public Date getCreatedTime() {
return createdTime;
}
/**
* 设置 创建时间.
*
* @param createdTime 创建时间.
*/
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
/**
* 获取 更新时间.
*
* @return 更新时间.
*/
public Date getUpdatedTime() {
return updatedTime;
}
/**
* 设置 更新时间.
*
* @param updatedTime 更新时间.
*/
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
@Override
protected Serializable pkVal() {
return this.id;
}
}

View File

@ -0,0 +1,141 @@
package com.enzhico.jwt.common.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.activerecord.Model;
import java.io.Serializable;
/**
* 角色表
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
@TableName(value = "t_role")
public class Role extends Model<Role> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 角色名称
*/
private String role;
/**
* 角色说明
*/
private String description;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 获取 主键ID.
*
* @return 主键ID.
*/
public Integer getId() {
return id;
}
/**
* 设置 主键ID.
*
* @param id 主键ID.
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取 角色名称.
*
* @return 角色名称.
*/
public String getRole() {
return role;
}
/**
* 设置 角色名称.
*
* @param role 角色名称.
*/
public void setRole(String role) {
this.role = role;
}
/**
* 获取 角色说明.
*
* @return 角色说明.
*/
public String getDescription() {
return description;
}
/**
* 设置 角色说明.
*
* @param description 角色说明.
*/
public void setDescription(String description) {
this.description = description;
}
/**
* 获取 创建时间.
*
* @return 创建时间.
*/
public Date getCreatedTime() {
return createdTime;
}
/**
* 设置 创建时间.
*
* @param createdTime 创建时间.
*/
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
/**
* 获取 更新时间.
*
* @return 更新时间.
*/
public Date getUpdatedTime() {
return updatedTime;
}
/**
* 设置 更新时间.
*
* @param updatedTime 更新时间.
*/
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
@Override
protected Serializable pkVal() {
return this.id;
}
}

View File

@ -0,0 +1,141 @@
package com.enzhico.jwt.common.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.activerecord.Model;
import java.io.Serializable;
/**
* 角色权限关联表
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
@TableName(value = "t_role_permission")
public class RolePermission extends Model<RolePermission> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 角色ID
*/
private Integer roleId;
/**
* 权限ID
*/
private Integer permissionId;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 获取 主键ID.
*
* @return 主键ID.
*/
public Integer getId() {
return id;
}
/**
* 设置 主键ID.
*
* @param id 主键ID.
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取 角色ID.
*
* @return 角色ID.
*/
public Integer getRoleId() {
return roleId;
}
/**
* 设置 角色ID.
*
* @param roleId 角色ID.
*/
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
/**
* 获取 权限ID.
*
* @return 权限ID.
*/
public Integer getPermissionId() {
return permissionId;
}
/**
* 设置 权限ID.
*
* @param permissionId 权限ID.
*/
public void setPermissionId(Integer permissionId) {
this.permissionId = permissionId;
}
/**
* 获取 创建时间.
*
* @return 创建时间.
*/
public Date getCreatedTime() {
return createdTime;
}
/**
* 设置 创建时间.
*
* @param createdTime 创建时间.
*/
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
/**
* 获取 更新时间.
*
* @return 更新时间.
*/
public Date getUpdatedTime() {
return updatedTime;
}
/**
* 设置 更新时间.
*
* @param updatedTime 更新时间.
*/
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
@Override
protected Serializable pkVal() {
return this.id;
}
}

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt.common.dao.repository;
import com.enzhico.jwt.common.dao.entity.App;
import com.baomidou.mybatisplus.mapper.BaseMapper;
/**
* APP表 Mapper
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
public interface AppMapper extends BaseMapper<App> {
}

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt.common.dao.repository;
import com.enzhico.jwt.common.dao.entity.AppPublish;
import com.baomidou.mybatisplus.mapper.BaseMapper;
/**
* APP发布表 Mapper
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
public interface AppPublishMapper extends BaseMapper<AppPublish> {
}

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt.common.dao.repository;
import com.enzhico.jwt.common.dao.entity.Manager;
import com.baomidou.mybatisplus.mapper.BaseMapper;
/**
* 后台管理用户表 Mapper
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
public interface ManagerMapper extends BaseMapper<Manager> {
}

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt.common.dao.repository;
import com.enzhico.jwt.common.dao.entity.ManagerRole;
import com.baomidou.mybatisplus.mapper.BaseMapper;
/**
* 用户角色关联表 Mapper
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
public interface ManagerRoleMapper extends BaseMapper<ManagerRole> {
}

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt.common.dao.repository;
import com.enzhico.jwt.common.dao.entity.OperationLog;
import com.baomidou.mybatisplus.mapper.BaseMapper;
/**
* 操作日志表 Mapper
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
public interface OperationLogMapper extends BaseMapper<OperationLog> {
}

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt.common.dao.repository;
import com.enzhico.jwt.common.dao.entity.Permission;
import com.baomidou.mybatisplus.mapper.BaseMapper;
/**
* 权限表 Mapper
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
public interface PermissionMapper extends BaseMapper<Permission> {
}

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt.common.dao.repository;
import com.enzhico.jwt.common.dao.entity.PosHistory;
import com.baomidou.mybatisplus.mapper.BaseMapper;
/**
* POS机历史归属表 Mapper
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
public interface PosHistoryMapper extends BaseMapper<PosHistory> {
}

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt.common.dao.repository;
import com.enzhico.jwt.common.dao.entity.Pos;
import com.baomidou.mybatisplus.mapper.BaseMapper;
/**
* POS机表 Mapper
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
public interface PosMapper extends BaseMapper<Pos> {
}

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt.common.dao.repository;
import com.enzhico.jwt.common.dao.entity.PosMonitor;
import com.baomidou.mybatisplus.mapper.BaseMapper;
/**
* POS机监控表 Mapper
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
public interface PosMonitorMapper extends BaseMapper<PosMonitor> {
}

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt.common.dao.repository;
import com.enzhico.jwt.common.dao.entity.Project;
import com.baomidou.mybatisplus.mapper.BaseMapper;
/**
* 项目表 Mapper
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
public interface ProjectMapper extends BaseMapper<Project> {
}

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt.common.dao.repository;
import com.enzhico.jwt.common.dao.entity.ProjectUser;
import com.baomidou.mybatisplus.mapper.BaseMapper;
/**
* 项目用户关联表 Mapper
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
public interface ProjectUserMapper extends BaseMapper<ProjectUser> {
}

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt.common.dao.repository;
import com.enzhico.jwt.common.dao.entity.Role;
import com.baomidou.mybatisplus.mapper.BaseMapper;
/**
* 角色表 Mapper
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
public interface RoleMapper extends BaseMapper<Role> {
}

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt.common.dao.repository;
import com.enzhico.jwt.common.dao.entity.RolePermission;
import com.baomidou.mybatisplus.mapper.BaseMapper;
/**
* 角色权限关联表 Mapper
*
* @author 熊能
* @version 1.0
* @since 2018/01/02
*/
public interface RolePermissionMapper extends BaseMapper<RolePermission> {
}

View File

@ -0,0 +1,41 @@
package com.enzhico.jwt.common.util;
/**
* 常用工具类字符串数字相关
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/15
*/
public class CommonUtil {
/**
* 检查某版本是否比现在版本更大些
*
* @param version 某版本
* @param nowVersion 现在使用的版本
* @return 是否版本数更大
*/
public static boolean isNewer(String version, String nowVersion) {
try {
String[] versions = version.split("\\.");
String[] nowVersions = nowVersion.split("\\.");
if (versions.length != nowVersions.length) {
return false;
}
int sum = 0;
for (String v : versions) {
sum += sum * 10 + Integer.valueOf(v);
}
int nowSum = 0;
for (String nv : nowVersions) {
nowSum += nowSum * 10 + Integer.valueOf(nv);
}
return sum > nowSum;
} catch (NumberFormatException e) {
return false;
}
}
}

View File

@ -0,0 +1,296 @@
/**
* Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.enzhico.jwt.common.util;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class DateUtil {
private final static SimpleDateFormat sdfYear = new SimpleDateFormat("yyyy");
private final static SimpleDateFormat sdfDay = new SimpleDateFormat("yyyy-MM-dd");
private final static SimpleDateFormat sdfDays = new SimpleDateFormat("yyyyMMdd");
private final static SimpleDateFormat sdfTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private final static SimpleDateFormat sdfmsTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
private final static SimpleDateFormat allTime = new SimpleDateFormat("yyyyMMddHHmmss");
private final static SimpleDateFormat sdfDay_ = new SimpleDateFormat("yyyy/MM/dd");
/**
* 获取YYYY格式
*
* @return
*/
public static String getYear() {
return sdfYear.format(new Date());
}
/**
* 获取YYYY格式
*
* @return
*/
public static String getYear(Date date) {
return sdfYear.format(date);
}
/**
* 获取YYYY-MM-DD格式
*
* @return
*/
public static String getDay() {
return sdfDay.format(new Date());
}
/**
* 获取YYYY-MM-DD格式
*
* @return
*/
public static String getDay(Date date) {
return sdfDay.format(date);
}
/**
* 获取YYYYMMDD格式
*
* @return
*/
public static String getDays() {
return sdfDays.format(new Date());
}
/**
* 获取YYYYMMDD格式
*
* @return
*/
public static String getDays(Date date) {
return sdfDays.format(date);
}
/**
* 获取YYYY/MM/DD格式
*
* @return
*/
public static String getDays_(Date date) {
return sdfDay_.format(date);
}
/**
* 获取YYYY-MM-DD HH:mm:ss格式
*
* @return
*/
public static String getTime() {
return sdfTime.format(new Date());
}
/**
* 获取YYYY-MM-DD HH:mm:ss.SSS格式
*
* @return
*/
public static String getMsTime() {
return sdfmsTime.format(new Date());
}
/**
* 获取YYYYMMDDHHmmss格式
*
* @return
*/
public static String getAllTime() {
return allTime.format(new Date());
}
/**
* 获取YYYY-MM-DD HH:mm:ss格式
*
* @return
*/
public static String getTime(Date date) {
return sdfTime.format(date);
}
/**
* @param s
* @param e
* @return boolean
* @throws
* @Title: compareDate
* @Description:(日期比较如果s>=e 返回true 否则返回false)
* @author luguosui
*/
public static boolean compareDate(String s, String e) {
if (parseDate(s) == null || parseDate(e) == null) {
return false;
}
return parseDate(s).getTime() >= parseDate(e).getTime();
}
/**
* 格式化日期
*
* @return
*/
public static Date parseDate(String date) {
try {
return sdfDay.parse(date);
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
/**
* 格式化日期
*
* @return
*/
public static Date parseTime(String date) {
try {
return sdfTime.parse(date);
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
/**
* 格式化日期
*
* @return
*/
public static Date parse(String date, String pattern) {
DateFormat fmt = new SimpleDateFormat(pattern);
try {
return fmt.parse(date);
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
/**
* 格式化日期
*
* @return
*/
public static String format(Date date, String pattern) {
DateFormat fmt = new SimpleDateFormat(pattern);
return fmt.format(date);
}
/**
* 把日期转换为Timestamp
*
* @param date
* @return
*/
public static Timestamp format(Date date) {
return new Timestamp(date.getTime());
}
/**
* 校验日期是否合法
*
* @return
*/
public static boolean isValidDate(String s) {
try {
sdfTime.parse(s);
return true;
} catch (Exception e) {
// 如果throw java.text.ParseException或者NullPointerException就说明格式不对
return false;
}
}
/**
* 校验日期是否合法
*
* @return
*/
public static boolean isValidDate(String s, String pattern) {
DateFormat fmt = new SimpleDateFormat(pattern);
try {
fmt.parse(s);
return true;
} catch (Exception e) {
// 如果throw java.text.ParseException或者NullPointerException就说明格式不对
return false;
}
}
/**
* 获取指定日期偏移指定时间后的时间
*
* @param date 基准日期
* @param calendarField 偏移的粒度大小小时月等使用Calendar中的常数
* @param offsite 偏移量正数为向后偏移负数为向前偏移
* @return 偏移后的日期
*/
public static Date offsiteDate(Date date, int calendarField, int offsite) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(calendarField, offsite);
return cal.getTime();
}
/**
* 返回日期零时
*
* @param date 目标日期
* @return 目标日期零时
*/
public static Date getDateStartTime(Date date) {
String str = format(date, "yyyyMMdd") + "000000";
try {
return allTime.parse(str);
} catch (ParseException e) {
return null;
}
}
/**
* 返回日期最后时间End
*
* @param date 目标日期
* @return 目标日日期最后时间
*/
public static Date getDateEndTime(Date date) {
String str = format(date, "yyyyMMdd") + "235959";
try {
return allTime.parse(str);
} catch (ParseException e) {
return null;
}
}
}

View File

@ -0,0 +1,173 @@
package com.enzhico.jwt.common.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.util.Date;
public class JWTUtil {
private static final Logger log = LoggerFactory.getLogger(JWTUtil.class);
// 过期时间5分钟
private static final long EXPIRE_TIME = 5 * 60 * 1000;
/**
* 校验token是否正确
*
* @param token 密钥
* @param secret 用户的密码
* @return 是否正确
*/
public static boolean verify(String token, String username, String secret) {
try {
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
.withClaim("username", username)
.build();
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception exception) {
log.error("校验token失败", exception);
return false;
}
}
/**
* 获得token中的信息无需secret解密也能获得
*
* @return token中包含的用户名
*/
public static String getUsername(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("username").asString();
} catch (JWTDecodeException e) {
return null;
}
}
/**
* 生成签名,5min后过期
*
* @param username 用户名
* @param secret 用户的密码
* @return 加密的token
*/
public static String sign(String username, String secret) {
try {
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
Algorithm algorithm = Algorithm.HMAC256(secret);
// 附带username信息
return JWT.create()
.withClaim("username", username)
.withExpiresAt(date)
.sign(algorithm);
} catch (UnsupportedEncodingException e) {
return null;
}
}
/*----------------------------以下是socket校验--------------------------*/
/**
* 生成Socket Token签名, 5min后过期
*
* @param username 用户名
* @param secret 用户的密码
* @param appid applicationId
* @param imei IMEI码
* @return 加密的token
*/
public static String signSocket(String username, String secret, String appid, String imei) {
try {
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
Algorithm algorithm = Algorithm.HMAC256(secret);
// 附带username信息
return JWT.create()
.withClaim("username", username)
.withClaim("appid", appid)
.withClaim("imei", imei)
.withExpiresAt(date)
.sign(algorithm);
} catch (UnsupportedEncodingException e) {
return null;
}
}
/**
* 校验token是否正确
*
* @param token 密钥
* @param secret 用户的密码
* @return 是否正确
*/
public static boolean verifySocket(String token, String secret) {
try {
DecodedJWT jwt1 = JWT.decode(token);
String username = jwt1.getClaim("username").asString();
String appid = jwt1.getClaim("appid").asString();
String imei = jwt1.getClaim("imei").asString();
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
.withClaim("username", username)
.withClaim("appid", appid)
.withClaim("imei", imei)
.build();
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception exception) {
log.error("校验token失败", exception);
return false;
}
}
/**
* 获得token中的信息无需secret解密也能获得
*
* @return token中包含的用户名
*/
public static String getSocketUsername(String token) {
try {
DecodedJWT jwt1 = JWT.decode(token);
return jwt1.getClaim("username").asString();
} catch (JWTDecodeException e) {
return null;
}
}
/**
* 获得token中的信息无需secret解密也能获得
*
* @return token中包含的Appid
*/
public static String getSocketAppid(String token) {
try {
DecodedJWT jwt1 = JWT.decode(token);
return jwt1.getClaim("appid").asString();
} catch (JWTDecodeException e) {
return null;
}
}
/**
* 获得token中的信息无需secret解密也能获得
*
* @return token中包含的IMEI码
*/
public static String getSocketImei(String token) {
try {
DecodedJWT jwt1 = JWT.decode(token);
return jwt1.getClaim("imei").asString();
} catch (JWTDecodeException e) {
return null;
}
}
}

View File

@ -0,0 +1,47 @@
package com.enzhico.jwt.common.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
/**
* 对象和Json转换器
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/18
*/
public class JsonConverter {
public static JSONObject objectToJSONObject(Object object) {
try {
String jsonString = new ObjectMapper().writeValueAsString(object);
return new JSONObject(jsonString);
} catch (JSONException | JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
public static JSONArray objectToJSONArray(Object object) {
try {
String jsonString = new ObjectMapper().writeValueAsString(object);
return new JSONArray(jsonString);
} catch (JSONException | JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
public static <T> T jsonObjectToObject(Object jsonObject, Class<T> clazz) {
try {
// List<Car> listCar = objectMapper.readValue(jsonCarArray, new TypeReference<List<Car>>(){});
return new ObjectMapper().readValue(jsonObject.toString(), clazz);
} catch (IOException e) {
return null;
}
}
}

View File

@ -0,0 +1,47 @@
package com.enzhico.jwt.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import com.enzhico.jwt.config.properties.DruidProperties;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.annotation.Resource;
/**
* MybatisPlus配置
*
* @author xiongneng
* @since 2017/5/20 21:58
*/
@Configuration
@EnableTransactionManagement(order = 2)
@MapperScan(basePackages = {
"com.enzhico.jwt.common.dao.repository",
"com.enzhico.jwt.dao.repository"})
public class MybatisPlusConfig {
@Resource
private DruidProperties druidProperties;
/**
* 单数据源连接池配置
*/
@Bean
public DruidDataSource singleDatasource() {
DruidDataSource dataSource = new DruidDataSource();
druidProperties.config(dataSource);
return dataSource;
}
/**
* mybatis-plus分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}

View File

@ -0,0 +1,72 @@
package com.enzhico.jwt.config;
import com.corundumstudio.socketio.AuthorizationListener;
import com.corundumstudio.socketio.HandshakeData;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.SpringAnnotationScanner;
import com.enzhico.jwt.common.util.JWTUtil;
import com.enzhico.jwt.config.properties.MyProperties;
import com.enzhico.jwt.dao.entity.ManagerInfo;
import com.enzhico.jwt.service.ApiService;
import com.enzhico.jwt.service.ManagerInfoService;
import com.enzhico.jwt.shiro.ShiroKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
/**
* NettySocketConfig
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/19
*/
@Configuration
public class NettySocketConfig {
@Resource
private MyProperties myProperties;
@Resource
private ApiService apiService;
@Resource
private ManagerInfoService managerInfoService;
private static final Logger logger = LoggerFactory.getLogger(NettySocketConfig.class);
@Bean
public SocketIOServer socketIOServer() {
/*
* 创建Socket并设置监听端口
*/
com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
// 设置主机名默认是0.0.0.0
// config.setHostname("localhost");
// 设置监听端口
config.setPort(myProperties.getSocketPort());
// 协议升级超时时间毫秒默认10000HTTP握手升级为ws协议超时时间
config.setUpgradeTimeout(10000);
// Ping消息间隔毫秒默认25000客户端向服务器发送一条心跳消息间隔
config.setPingInterval(myProperties.getPingInterval());
// Ping消息超时时间毫秒默认60000这个时间间隔内没有接收到心跳消息就会发送超时事件
config.setPingTimeout(myProperties.getPingTimeout());
// 握手协议参数使用JWT的Token认证方案
config.setAuthorizationListener(data -> {
// 可以使用如下代码获取用户密码信息
String token = data.getSingleUrlParam("token");
String username = JWTUtil.getSocketUsername(token);
ManagerInfo managerInfo = managerInfoService.findByUsername(username);
return JWTUtil.verifySocket(token, managerInfo.getPassword());
});
return new SocketIOServer(config);
}
@Bean
public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {
return new SpringAnnotationScanner(socketServer);
}
}

View File

@ -0,0 +1,134 @@
package com.enzhico.jwt.config;
import com.enzhico.jwt.shiro.JWTFilter;
import com.enzhico.jwt.shiro.MyShiroRealm;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Description : Apache Shiro 核心通过 Filter 来实现就好像SpringMvc 通过DispachServlet 来主控制一样
* 既然是使用 Filter 一般也就能猜到是通过URL规则来进行过滤和权限校验所以我们需要定义一系列关于URL的规则和访问权限
*/
@Configuration
@Order(1)
public class ShiroConfig {
/**
* ShiroFilterFactoryBean 处理拦截资源文件问题
* 注意单独一个ShiroFilterFactoryBean配置是或报错的以为在
* 初始化ShiroFilterFactoryBean的时候需要注入SecurityManager Filter Chain定义说明
* 1一个URL可以配置多个Filter使用逗号分隔
* 2当设置多个过滤器时全部验证通过才视为通过
* 3部分过滤器可指定参数如permsroles
*/
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
//验证码过滤器
Map<String, Filter> filtersMap = shiroFilterFactoryBean.getFilters();
filtersMap.put("jwt", new JWTFilter());
shiroFilterFactoryBean.setFilters(filtersMap);
// 拦截器
//rest比如/admins/user/**=rest[user],根据请求的方法相当于/admins/user/**=perms[usermethod] ,其中method为postgetdelete等
//port比如/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal//serverName8081?queryString,其中schmal是协议http或https等serverName是你访问的host,8081是url配置里port的端口queryString是你访问的url里的后面的参数
//perms比如/admins/user/**=perms[useradd*],perms参数可以写多个多个时必须加上引号并且参数之间用逗号分割比如/admins/user/**=perms["useradd*,usermodify*"]当有多个参数时必须每个参数都通过才通过想当于isPermitedAll()方法
//roles比如/admins/user/**=roles[admin],参数可以写多个多个时必须加上引号并且参数之间用逗号分割当有多个参数时比如/admins/user/**=roles["admin,guest"],每个参数通过才算通过相当于hasAllRoles()方法//要实现or的效果看http://zgzty.blog.163.com/blog/static/83831226201302983358670/
//anon比如/admins/**=anon 没有参数表示可以匿名使用
//authc比如/admins/user/**=authc表示需要认证才能使用没有参数
//authcBasic比如/admins/user/**=authcBasic没有参数表示httpBasic认证
//ssl比如/admins/user/**=ssl没有参数表示安全的url请求协议为https
//user比如/admins/user/**=user没有参数表示必须存在用户当登入操作时不做检查
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// swagger接口文档
filterChainDefinitionMap.put("/v2/api-docs", "anon");
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/swagger-resources/**", "anon");
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
filterChainDefinitionMap.put("/doc.html", "anon");
// 其他的
filterChainDefinitionMap.put("/**", "jwt");
// 访问401和404页面不通过我们的Filter
filterChainDefinitionMap.put("/401", "anon");
filterChainDefinitionMap.put("/404", "anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(myShiroRealm());
//注入缓存管理器
securityManager.setCacheManager(ehCacheManager());
/*
* 关闭shiro自带的session详情见文档
* http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
*/
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
securityManager.setSubjectDAO(subjectDAO);
return securityManager;
}
/**
* 身份认证realm; (这个需要自己写账号密码校验权限等)
*/
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
/**
* 开启shiro aop注解支持. 使用代理方式; 所以需要开启代码支持;
*
* @param securityManager 安全管理器
* @return 授权Advisor
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* shiro缓存管理器;
* 需要注入对应的其它的实体类中
* 1安全管理器securityManager
* 可见securityManager是整个shiro的核心
*
* @return
*/
@Bean
public EhCacheManager ehCacheManager() {
EhCacheManager cacheManager = new EhCacheManager();
cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
return cacheManager;
}
}

View File

@ -0,0 +1,55 @@
package com.enzhico.jwt.config;
import com.google.common.collect.Sets;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* Swagger2的Java配置类
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/7
*/
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.produces(Sets.newHashSet("application/json"))
.consumes(Sets.newHashSet("application/json"))
.protocols(Sets.newHashSet("http", "https"))
.apiInfo(apiInfo())
.forCodeGeneration(true)
.select()
// 指定controller存放的目录路径
.apis(RequestHandlerSelectors.basePackage("com.enzhico.jwt.api"))
// .paths(PathSelectors.ant("/api/v1/*"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
// 文档标题
.title("系统API服务")
// 文档描述
.description("系统API接口文档")
// .termsOfServiceUrl("https://github.com/yidao620c")
.version("v1")
// .license("MIT 协议")
// .licenseUrl("http://www.opensource.org/licenses/MIT")
// .contact(new Contact("熊能","https://github.com/yidao620c","yidao620@gmail.com"))
.build();
}
}

View File

@ -0,0 +1,102 @@
package com.enzhico.jwt.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.support.spring.stat.BeanTypeAutoProxyCreator;
import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextListener;
/**
* web 配置类
*
* @author xiongneng
* @since 2016年11月12日 下午5:03:32
*/
@Configuration
public class WebConfig {
/**
* druidServlet注册
*/
@Bean
public ServletRegistrationBean druidServletRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(new StatViewServlet());
registration.addUrlMappings("/druid/*");
return registration;
}
/**
* druid监控 配置URI拦截策略
*
* @return
*/
@Bean
public FilterRegistrationBean druidStatFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
//添加过滤规则.
filterRegistrationBean.addUrlPatterns("/*");
//添加不需要忽略的格式信息.
filterRegistrationBean.addInitParameter(
"exclusions", "/static/*,*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid,/druid/*");
//用于session监控页面的用户名显示 需要登录后主动将username注入到session里
filterRegistrationBean.addInitParameter("principalSessionName", "username");
return filterRegistrationBean;
}
/**
* druid数据库连接池监控
*/
@Bean
public DruidStatInterceptor druidStatInterceptor() {
return new DruidStatInterceptor();
}
@Bean
public JdkRegexpMethodPointcut druidStatPointcut() {
JdkRegexpMethodPointcut druidStatPointcut = new JdkRegexpMethodPointcut();
String patterns = "com.enzhico.jwt.*.service.*";
//可以set多个
druidStatPointcut.setPatterns(patterns);
return druidStatPointcut;
}
/**
* druid数据库连接池监控
*/
@Bean
public BeanTypeAutoProxyCreator beanTypeAutoProxyCreator() {
BeanTypeAutoProxyCreator beanTypeAutoProxyCreator = new BeanTypeAutoProxyCreator();
beanTypeAutoProxyCreator.setTargetBeanType(DruidDataSource.class);
beanTypeAutoProxyCreator.setInterceptorNames("druidStatInterceptor");
return beanTypeAutoProxyCreator;
}
/**
* druid 为druidStatPointcut添加拦截
*
* @return
*/
@Bean
public Advisor druidStatAdvisor() {
return new DefaultPointcutAdvisor(druidStatPointcut(), druidStatInterceptor());
}
/**
* RequestContextListener注册
*/
@Bean
public ServletListenerRegistrationBean<RequestContextListener> requestContextListenerRegistration() {
return new ServletListenerRegistrationBean<>(new RequestContextListener());
}
}

View File

@ -0,0 +1,249 @@
package com.enzhico.jwt.config.properties;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.util.JdbcConstants;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.sql.SQLException;
/**
* <p>数据库数据源配置</p>
* <p>说明:这个类中包含了许多默认配置,若这些配置符合您的情况,您可以不用管,若不符合,建议不要修改本类,建议直接在"application.yml"中配置即可</p>
*
* @author xiongneng
* @since 2017-05-21 11:18
*/
@Component
@ConfigurationProperties(prefix = "spring.datasource")
public class DruidProperties {
private String url = "jdbc:mysql://127.0.0.1:3306/cloudsepay?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull";
private String username = "root";
private String password = "root";
private String driverClassName = "com.mysql.cj.jdbc.Driver";
private Integer initialSize = 10;
private Integer minIdle = 3;
private Integer maxActive = 60;
private Integer maxWait = 60000;
private Boolean removeAbandoned = true;
private Integer removeAbandonedTimeout = 180;
private Integer timeBetweenEvictionRunsMillis = 60000;
private Integer minEvictableIdleTimeMillis = 300000;
private String validationQuery = "SELECT 'x'";
private Boolean testWhileIdle = true;
private Boolean testOnBorrow = false;
private Boolean testOnReturn = false;
private Boolean poolPreparedStatements = true;
private Integer maxPoolPreparedStatementPerConnectionSize = 50;
private String filters = "stat";
public void config(DruidDataSource dataSource) {
dataSource.setDbType(JdbcConstants.MYSQL);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName(driverClassName);
dataSource.setInitialSize(initialSize); // 定义初始连接数
dataSource.setMinIdle(minIdle); // 最小空闲
dataSource.setMaxActive(maxActive); // 定义最大连接数
dataSource.setMaxWait(maxWait); // 获取连接等待超时的时间
dataSource.setRemoveAbandoned(removeAbandoned); // 超过时间限制是否回收
dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout); // 超过时间限制多长
// 配置间隔多久才进行一次检测检测需要关闭的空闲连接单位是毫秒
dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
// 配置一个连接在池中最小生存的时间单位是毫秒
dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
// 用来检测连接是否有效的sql要求是一个查询语句
dataSource.setValidationQuery(validationQuery);
// 申请连接的时候检测
dataSource.setTestWhileIdle(testWhileIdle);
// 申请连接时执行validationQuery检测连接是否有效配置为true会降低性能
dataSource.setTestOnBorrow(testOnBorrow);
// 归还连接时执行validationQuery检测连接是否有效配置为true会降低性能
dataSource.setTestOnReturn(testOnReturn);
// 打开PSCache并且指定每个连接上PSCache的大小
dataSource.setPoolPreparedStatements(poolPreparedStatements);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
// 属性类型是字符串通过别名的方式配置扩展插件常用的插件有
// 监控统计用的filter:stat
// 日志用的filter:log4j
// 防御SQL注入的filter:wall
try {
dataSource.setFilters(filters);
} catch (SQLException e) {
e.printStackTrace();
}
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public Integer getInitialSize() {
return initialSize;
}
public void setInitialSize(Integer initialSize) {
this.initialSize = initialSize;
}
public Integer getMinIdle() {
return minIdle;
}
public void setMinIdle(Integer minIdle) {
this.minIdle = minIdle;
}
public Integer getMaxActive() {
return maxActive;
}
public void setMaxActive(Integer maxActive) {
this.maxActive = maxActive;
}
public Integer getMaxWait() {
return maxWait;
}
public void setMaxWait(Integer maxWait) {
this.maxWait = maxWait;
}
public Integer getTimeBetweenEvictionRunsMillis() {
return timeBetweenEvictionRunsMillis;
}
public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) {
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
}
public Integer getMinEvictableIdleTimeMillis() {
return minEvictableIdleTimeMillis;
}
public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) {
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
}
public String getValidationQuery() {
return validationQuery;
}
public void setValidationQuery(String validationQuery) {
this.validationQuery = validationQuery;
}
public Boolean getTestWhileIdle() {
return testWhileIdle;
}
public void setTestWhileIdle(Boolean testWhileIdle) {
this.testWhileIdle = testWhileIdle;
}
public Boolean getTestOnBorrow() {
return testOnBorrow;
}
public void setTestOnBorrow(Boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
}
public Boolean getTestOnReturn() {
return testOnReturn;
}
public void setTestOnReturn(Boolean testOnReturn) {
this.testOnReturn = testOnReturn;
}
public Boolean getPoolPreparedStatements() {
return poolPreparedStatements;
}
public void setPoolPreparedStatements(Boolean poolPreparedStatements) {
this.poolPreparedStatements = poolPreparedStatements;
}
public Integer getMaxPoolPreparedStatementPerConnectionSize() {
return maxPoolPreparedStatementPerConnectionSize;
}
public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) {
this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;
}
public String getFilters() {
return filters;
}
public void setFilters(String filters) {
this.filters = filters;
}
public Boolean getRemoveAbandoned() {
return removeAbandoned;
}
public void setRemoveAbandoned(Boolean removeAbandoned) {
this.removeAbandoned = removeAbandoned;
}
public Integer getRemoveAbandonedTimeout() {
return removeAbandonedTimeout;
}
public void setRemoveAbandonedTimeout(Integer removeAbandonedTimeout) {
this.removeAbandonedTimeout = removeAbandonedTimeout;
}
}

View File

@ -0,0 +1,64 @@
package com.enzhico.jwt.config.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 本项目自定义配置
*
* @author xiongneng
* @since 2018/01/06 21:09
*/
@Component
@ConfigurationProperties(prefix = "enzhico")
public class MyProperties {
/**
* socket端口
*/
private Integer socketPort;
/**
* Ping消息间隔毫秒
*/
private Integer pingInterval;
/**
* Ping消息超时时间毫秒
*/
private Integer pingTimeout;
/**
* APK文件访问URL前缀
*/
private String apkUrlPrefix;
public Integer getSocketPort() {
return socketPort;
}
public void setSocketPort(Integer socketPort) {
this.socketPort = socketPort;
}
public Integer getPingInterval() {
return pingInterval;
}
public void setPingInterval(Integer pingInterval) {
this.pingInterval = pingInterval;
}
public Integer getPingTimeout() {
return pingTimeout;
}
public void setPingTimeout(Integer pingTimeout) {
this.pingTimeout = pingTimeout;
}
public String getApkUrlPrefix() {
return apkUrlPrefix;
}
public void setApkUrlPrefix(String apkUrlPrefix) {
this.apkUrlPrefix = apkUrlPrefix;
}
}

View File

@ -0,0 +1,79 @@
package com.enzhico.jwt.dao.entity;
import com.enzhico.jwt.common.constant.DictMap;
import com.enzhico.jwt.common.dao.entity.App;
import java.io.Serializable;
/**
* Description: App信息
*/
public class AppInfo extends App implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 操作者用户名
*/
private String operatorUsername;
/**
* 操作者姓名
*/
private String operatorName;
/**
* 归属项目名称
*/
private String projectName;
/**
* 发布范围显示
*/
private String publishRangeStr;
/**
* APK下载链接
*/
private String downloadUrl;
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public String getOperatorUsername() {
return operatorUsername;
}
public void setOperatorUsername(String operatorUsername) {
this.operatorUsername = operatorUsername;
}
public String getOperatorName() {
return operatorName;
}
public void setOperatorName(String operatorName) {
this.operatorName = operatorName;
}
public String getPublishRangeStr() {
return publishRangeStr;
}
public void setPublishRangeStr(String publishRangeStr) {
this.publishRangeStr = publishRangeStr;
}
public String getDownloadUrl() {
return downloadUrl;
}
public void setDownloadUrl(String downloadUrl) {
this.downloadUrl = downloadUrl;
}
public void buildTable() {
publishRangeStr = DictMap.value(DictMap.KEY_APP_PUBLISH_RANGE, getPublishRange());
}
}

View File

@ -0,0 +1,37 @@
package com.enzhico.jwt.dao.entity;
import java.util.List;
/**
* App名字和版本对应类
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/17
*/
public class AppVersionInfo {
/**
* 应用名称
*/
private String appName;
/**
* 版本号列表
*/
private List<String> versions;
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public List<String> getVersions() {
return versions;
}
public void setVersions(List<String> versions) {
this.versions = versions;
}
}

View File

@ -0,0 +1,27 @@
package com.enzhico.jwt.dao.entity;
/**
* FileInfo
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/10
*/
public class FileInfo {
private String filename;
public FileInfo() {
}
public FileInfo(String filename) {
this.filename = filename;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
}

View File

@ -0,0 +1,97 @@
package com.enzhico.jwt.dao.entity;
import com.enzhico.jwt.common.constant.DictMap;
import com.enzhico.jwt.common.dao.entity.Manager;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
* Description: 后台运维管理员信息
*/
public class ManagerInfo extends Manager implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 状态
*/
private String stateStr;
/**
* 所属项目id列表逗号分隔
*/
private String pids;
/**
* 所属项目名列表逗号分隔
*/
private String pnames;
/**
* 所属项目id列表
*/
private List<Integer> pidsList;
/**
* 一个管理员具有多个角色
*/
private List<SysRole> roles;// 一个用户具有多个角色
public ManagerInfo() {
}
public List<SysRole> getRoles() {
return roles;
}
public void setRoles(List<SysRole> roles) {
this.roles = roles;
}
/**
* 密码盐
*/
public String getCredentialsSalt() {
return getUsername() + getSalt();
}
@Override
public String toString() {
return "username:" + getUsername() + "|name=" + getName();
}
public String getStateStr() {
return stateStr;
}
public void setStateStr(String stateStr) {
this.stateStr = stateStr;
}
public String getPids() {
return pids;
}
public void setPids(String pids) {
this.pids = pids;
}
public List<Integer> getPidsList() {
return pidsList;
}
public void setPidsList(List<Integer> pidsList) {
this.pidsList = pidsList;
}
public String getPnames() {
return pnames;
}
public void setPnames(String pnames) {
this.pnames = pnames;
}
public void buildTable() {
stateStr = DictMap.value(DictMap.KEY_USER_STATUS, getState());
}
}

View File

@ -0,0 +1,58 @@
package com.enzhico.jwt.dao.entity;
import com.enzhico.jwt.common.constant.DictMap;
import com.enzhico.jwt.common.dao.entity.Pos;
import com.enzhico.jwt.common.dao.entity.PosMonitor;
import java.io.Serializable;
/**
* Description: 机具信息
*/
public class MonitorInfo extends PosMonitor implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 机具状态
*/
private String onlineStateStr;
/**
* 机具IMEI码
*/
private String imei;
/**
* 机具型号
*/
private String series;
public String getOnlineStateStr() {
return onlineStateStr;
}
public void setOnlineStateStr(String onlineStateStr) {
this.onlineStateStr = onlineStateStr;
}
public String getImei() {
return imei;
}
public void setImei(String imei) {
this.imei = imei;
}
public String getSeries() {
return series;
}
public void setSeries(String series) {
this.series = series;
}
public void buildTable() {
onlineStateStr = DictMap.value(DictMap.KEY_POS_MONITOR_STATUS, getOnlineState());
}
}

View File

@ -0,0 +1,40 @@
package com.enzhico.jwt.dao.entity;
import com.enzhico.jwt.common.constant.DictMap;
import com.enzhico.jwt.common.dao.entity.Pos;
import java.io.Serializable;
/**
* Description: 以网点为分组的机具信息
*/
public class PosGroupInfo extends Pos implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 归属项目名称
*/
private String projectName;
/**
* 机具数量网点分组
*/
private Integer posCount;
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public Integer getPosCount() {
return posCount;
}
public void setPosCount(Integer posCount) {
this.posCount = posCount;
}
}

View File

@ -0,0 +1,45 @@
package com.enzhico.jwt.dao.entity;
import com.enzhico.jwt.common.constant.DictMap;
import com.enzhico.jwt.common.dao.entity.Manager;
import com.enzhico.jwt.common.dao.entity.Pos;
import java.io.Serializable;
import java.util.List;
/**
* Description: 机具信息
*/
public class PosInfo extends Pos implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 机具状态
*/
private String posStateStr;
/**
* 归属项目名称
*/
private String projectName;
public String getPosStateStr() {
return posStateStr;
}
public void setPosStateStr(String posStateStr) {
this.posStateStr = posStateStr;
}
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public void buildTable() {
posStateStr = DictMap.value(DictMap.KEY_POS_POS_STATUS, getPosState());
}
}

View File

@ -0,0 +1,76 @@
package com.enzhico.jwt.dao.entity;
import org.springframework.web.multipart.MultipartFile;
/**
* APP版本发布参数
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/10
*/
public class PublishParam {
private String name;
private String version;
private String applicationId;
private String tips;
private Integer publishRange;
private String grayIds;
private MultipartFile file;
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;
}
public String getTips() {
return tips;
}
public void setTips(String tips) {
this.tips = tips;
}
public Integer getPublishRange() {
return publishRange;
}
public void setPublishRange(Integer publishRange) {
this.publishRange = publishRange;
}
public String getGrayIds() {
return grayIds;
}
public void setGrayIds(String grayIds) {
this.grayIds = grayIds;
}
public MultipartFile getFile() {
return file;
}
public void setFile(MultipartFile file) {
this.file = file;
}
public String getApplicationId() {
return applicationId;
}
public void setApplicationId(String applicationId) {
this.applicationId = applicationId;
}
}

View File

@ -0,0 +1,106 @@
package com.enzhico.jwt.dao.entity;
import java.util.Date;
import java.util.List;
/**
* 查询APP列表参数
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/8
*/
public class SearchApp {
private Integer pageNumber;
private Integer pageSize;
private String appName;
private String appVersion;
private Integer projectId;
private Integer publishRange;
private String publishtimeRange;
private Date publishTimeStart;
private Date publishTimeEnd;
private List<Integer> pidList;
public Integer getPageNumber() {
return pageNumber;
}
public void setPageNumber(Integer pageNumber) {
this.pageNumber = pageNumber;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getProjectId() {
return projectId;
}
public void setProjectId(Integer projectId) {
this.projectId = projectId;
}
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getAppVersion() {
return appVersion;
}
public void setAppVersion(String appVersion) {
this.appVersion = appVersion;
}
public Integer getPublishRange() {
return publishRange;
}
public void setPublishRange(Integer publishRange) {
this.publishRange = publishRange;
}
public Date getPublishTimeStart() {
return publishTimeStart;
}
public void setPublishTimeStart(Date publishTimeStart) {
this.publishTimeStart = publishTimeStart;
}
public Date getPublishTimeEnd() {
return publishTimeEnd;
}
public void setPublishTimeEnd(Date publishTimeEnd) {
this.publishTimeEnd = publishTimeEnd;
}
public String getPublishtimeRange() {
return publishtimeRange;
}
public void setPublishtimeRange(String publishtimeRange) {
this.publishtimeRange = publishtimeRange;
}
public List<Integer> getPidList() {
return pidList;
}
public void setPidList(List<Integer> pidList) {
this.pidList = pidList;
}
}

View File

@ -0,0 +1,77 @@
package com.enzhico.jwt.dao.entity;
import java.util.List;
/**
* SearchUser
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/8
*/
public class SearchMonitor {
private Integer pageNumber;
private Integer pageSize;
private String imei;
private String location;
private Integer projectId;
private Integer onlineState;
private List<Integer> pidList;
public Integer getPageNumber() {
return pageNumber;
}
public void setPageNumber(Integer pageNumber) {
this.pageNumber = pageNumber;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public String getImei() {
return imei;
}
public void setImei(String imei) {
this.imei = imei;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public Integer getProjectId() {
return projectId;
}
public void setProjectId(Integer projectId) {
this.projectId = projectId;
}
public Integer getOnlineState() {
return onlineState;
}
public void setOnlineState(Integer onlineState) {
this.onlineState = onlineState;
}
public List<Integer> getPidList() {
return pidList;
}
public void setPidList(List<Integer> pidList) {
this.pidList = pidList;
}
}

View File

@ -0,0 +1,69 @@
package com.enzhico.jwt.dao.entity;
import java.util.Date;
import java.util.List;
/**
* SearchUser
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/8
*/
public class SearchPos {
private Integer pageNumber;
private Integer pageSize;
private String imei;
private String location;
private Integer projectId;
private List<Integer> pidList;
public Integer getPageNumber() {
return pageNumber;
}
public void setPageNumber(Integer pageNumber) {
this.pageNumber = pageNumber;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public String getImei() {
return imei;
}
public void setImei(String imei) {
this.imei = imei;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public Integer getProjectId() {
return projectId;
}
public void setProjectId(Integer projectId) {
this.projectId = projectId;
}
public List<Integer> getPidList() {
return pidList;
}
public void setPidList(List<Integer> pidList) {
this.pidList = pidList;
}
}

View File

@ -0,0 +1,85 @@
package com.enzhico.jwt.dao.entity;
import java.util.Date;
/**
* SearchUser
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/8
*/
public class SearchUser {
private Integer pageNumber;
private Integer pageSize;
private String username;
private String phone;
private Integer state;
private String createdTime;
private Date createdTimeStart;
private Date createdTimeEnd;
public Integer getPageNumber() {
return pageNumber;
}
public void setPageNumber(Integer pageNumber) {
this.pageNumber = pageNumber;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
public String getCreatedTime() {
return createdTime;
}
public void setCreatedTime(String createdTime) {
this.createdTime = createdTime;
}
public Date getCreatedTimeStart() {
return createdTimeStart;
}
public void setCreatedTimeStart(Date createdTimeStart) {
this.createdTimeStart = createdTimeStart;
}
public Date getCreatedTimeEnd() {
return createdTimeEnd;
}
public void setCreatedTimeEnd(Date createdTimeEnd) {
this.createdTimeEnd = createdTimeEnd;
}
}

View File

@ -0,0 +1,29 @@
package com.enzhico.jwt.dao.entity;
import com.enzhico.jwt.common.dao.entity.Permission;
import com.enzhico.jwt.common.dao.entity.Role;
import java.io.Serializable;
import java.util.List;
/**
* Description : 角色信息
*/
public class SysRole extends Role implements Serializable {
private static final long serialVersionUID = 1L;
// 拥有的权限列表
private List<Permission> permissions;
public SysRole() {
}
public List<Permission> getPermissions() {
return permissions;
}
public void setPermissions(List<Permission> permissions) {
this.permissions = permissions;
}
}

View File

@ -0,0 +1,26 @@
package com.enzhico.jwt.dao.repository;
import com.enzhico.jwt.api.model.VersionParam;
import com.enzhico.jwt.api.model.VersionResult;
import org.apache.ibatis.annotations.Param;
/**
* Description :
*/
public interface ApiDao {
/**
* 查询版本发布
*
* @param param
* @return
*/
VersionResult selectPublishCount(VersionParam param);
/**
* 根据imei码获取session id
*
* @param imei imei码
* @return session id
*/
String selectSessionId(@Param("imei") String imei);
}

View File

@ -0,0 +1,20 @@
package com.enzhico.jwt.dao.repository;
import com.baomidou.mybatisplus.plugins.pagination.Pagination;
import com.enzhico.jwt.common.dao.repository.ManagerMapper;
import com.enzhico.jwt.dao.entity.ManagerInfo;
import com.enzhico.jwt.dao.entity.SearchUser;
import java.util.List;
import java.util.Map;
/**
* Description :
*/
public interface ManagerInfoDao extends ManagerMapper {
ManagerInfo findByUsername(String username);
List<ManagerInfo> selectUsers(Pagination page, SearchUser param);
ManagerInfo selectUser(Integer id);
}

View File

@ -0,0 +1,32 @@
<?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.enzhico.jwt.dao.repository.ApiDao">
<!-- 查询是否存在发布的新版本-->
<select id="selectPublishCount" parameterType="versionParam" resultType="versionResult">
SELECT
A.name AS appName,
A.version AS version,
A.tips AS tips,
A.publishtime AS publishtime
FROM t_app A
LEFT OUTER JOIN t_app_publish B ON A.id=B.app_id
LEFT OUTER JOIN t_pos C ON B.pos_id=C.id
WHERE
A.application_id=#{applicationId}
AND A.version &lt;&gt; #{version}
AND (A.publish_range=1 OR A.publish_range=2 AND C.imei=#{imei})
ORDER BY A.publishtime DESC
LIMIT 1
</select>
<select id="selectSessionId" resultType="string" parameterType="string">
SELECT A.session_id
FROM
t_pos_monitor A
LEFT OUTER JOIN t_pos B ON A.pos_id=B.id
WHERE B.imei = #{imei}
LIMIT 1
</select>
</mapper>

View File

@ -0,0 +1,106 @@
<?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.enzhico.jwt.dao.repository.ManagerInfoDao">
<resultMap id="ManagerInfoMap" type="managerInfo">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="name" column="name"/>
<result property="password" column="password"/>
<result property="salt" column="salt"/>
<result property="state" column="state"/>
<collection property="roles" ofType="sysRole">
<id property="id" column="role_id"/>
<result property="role" column="role_role"/>
<collection property="permissions" ofType="permission">
<id property="id" column="perm_id"/>
<result property="permission" column="perm_permission"/>
</collection>
</collection>
<collection property="pidsList" ofType="integer">
<result column="project_id"/>
</collection>
</resultMap>
<select id="findByUsername" resultMap="ManagerInfoMap">
SELECT DISTINCT
A.id AS id,
A.username AS username,
A.name AS name,
A.password AS password,
A.salt AS salt,
A.state AS state,
C.id AS role_id,
C.role AS role_role,
E.id AS perm_id,
E.permission AS perm_permission,
F.project_id AS project_id
FROM t_manager A
LEFT JOIN t_manager_role B ON A.id=B.manager_id
LEFT JOIN t_role C ON B.role_id=C.id
LEFT JOIN t_role_permission D ON C.id=D.role_id
LEFT JOIN t_permission E ON D.permission_Id=E.id
LEFT JOIN t_project_user F ON A.id=F.user_id
WHERE username=#{username}
</select>
<resultMap id="ManagerInfoMap2" type="managerInfo">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="name" column="name"/>
<result property="password" column="password"/>
<result property="phone" column="phone"/>
<result property="tips" column="tips"/>
<result property="state" column="state"/>
<result property="createdTime" column="createdTime"/>
<result property="pids" column="pids"/>
<result property="pnames" column="pnames"/>
</resultMap>
<select id="selectUsers" resultMap="ManagerInfoMap2" parameterType="searchUser">
SELECT DISTINCT
A.id AS id,
A.username AS username,
A.name AS name,
A.phone AS phone,
A.tips AS tips,
A.state AS state,
A.created_time AS createdTime,
group_concat(C.id) AS pids,
group_concat(C.name) AS pnames
FROM t_manager A
LEFT OUTER JOIN t_project_user B ON A.id=B.user_id
LEFT OUTER JOIN t_project C ON B.project_id=C.id
<where>
<if test='username != null and username != ""'>
(A.username LIKE "%"#{username}"%" OR A.name LIKE "%"#{username}"%")
</if>
<if test='phone != null and phone != ""'>
AND A.phone = #{phone}
</if>
<if test='state != null and state != 0'>
AND A.state = #{state}
</if>
<if test='createdTimeStart != null and createdTimeEnd != null'>
AND A.created_time BETWEEN #{createdTimeStart} AND #{createdTimeEnd}
</if>
</where>
GROUP BY A.id
</select>
<select id="selectUser" parameterType="int" resultType="managerInfo">
SELECT DISTINCT
A.id AS id,
A.username AS username,
A.name AS name,
A.phone AS phone,
A.tips AS tips,
A.state AS state,
A.created_time AS createdTime,
group_concat(C.id) AS pids
FROM t_manager A
LEFT OUTER JOIN t_project_user B ON A.id=B.user_id
LEFT OUTER JOIN t_project C ON B.project_id=C.id
WHERE A.id=#{id}
GROUP BY A.id
</select>
</mapper>

View File

@ -0,0 +1,14 @@
package com.enzhico.jwt.exception;
import org.apache.shiro.authc.AuthenticationException;
/**
* 禁用用户异常
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/12
*/
public class ForbiddenUserException extends AuthenticationException {
}

View File

@ -0,0 +1,18 @@
package com.enzhico.jwt.exception;
/**
* UnauthorizedException
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/22
*/
public class UnauthorizedException extends RuntimeException {
public UnauthorizedException(String msg) {
super(msg);
}
public UnauthorizedException() {
super();
}
}

View File

@ -0,0 +1,344 @@
package com.enzhico.jwt.handler;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import com.enzhico.jwt.api.model.*;
import com.enzhico.jwt.common.dao.entity.Pos;
import com.enzhico.jwt.common.dao.entity.Project;
import com.enzhico.jwt.common.util.JWTUtil;
import com.enzhico.jwt.service.ApiService;
import io.socket.client.Socket;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.UUID;
/**
* 消息事件处理器
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/19
*/
@Component
public class MessageEventHandler {
private final SocketIOServer server;
private final ApiService apiService;
private static final Logger logger = LoggerFactory.getLogger(MessageEventHandler.class);
@Autowired
public MessageEventHandler(SocketIOServer server, ApiService apiService) {
this.server = server;
this.apiService = apiService;
}
//添加connect事件当客户端发起连接时调用
@OnConnect
public void onConnect(SocketIOClient client) {
if (client != null) {
String token = client.getHandshakeData().getSingleUrlParam("token");
String applicationId = JWTUtil.getSocketAppid(token);
String imei = JWTUtil.getSocketImei(token);
String sessionId = client.getSessionId().toString();
logger.info("连接成功, applicationId=" + applicationId + ", imei=" + imei + ", sessionId=" + sessionId);
client.joinRoom(applicationId);
// 更新POS监控sessionId和状态
ReportParam param = new ReportParam();
param.setImei(imei);
apiService.updateJustState(param, sessionId, 1);
} else {
logger.error("客户端为空");
}
}
//添加@OnDisconnect事件客户端断开连接时调用刷新客户端信息
@OnDisconnect
public void onDisconnect(SocketIOClient client) {
String token = client.getHandshakeData().getSingleUrlParam("token");
String imei = JWTUtil.getSocketImei(token);
logger.info("客户端断开连接, imei=" + imei + ", sessionId=" + client.getSessionId().toString());
// 更新POS监控sessionId和状态
ReportParam param = new ReportParam();
param.setImei(imei);
apiService.updateJustState(param, "", 2);
client.disconnect();
}
// 消息接收入口
@OnEvent(value = Socket.EVENT_MESSAGE)
public void onEvent(SocketIOClient client, AckRequest ackRequest, Object data) {
logger.info("接收到客户端消息");
if (ackRequest.isAckRequested()) {
// send ack response with data to client
ackRequest.sendAckData("服务器回答Socket.EVENT_MESSAGE", "好的");
}
}
// 广播消息接收入口
@OnEvent(value = "broadcast")
public void onBroadcast(SocketIOClient client, AckRequest ackRequest, Object data) {
logger.info("接收到广播消息");
// 房间广播消息
String token = client.getHandshakeData().getSingleUrlParam("token");
String room = JWTUtil.getSocketAppid(token);
server.getRoomOperations(room).sendEvent("broadcast", "广播啦啦啦啦");
}
/**
* 入网绑定查询接口
* @param client 客户端
* @param ackRequest 回执消息
* @param imei imei码
*/
@OnEvent(value = "askJoin")
public void onAskJoin(SocketIOClient client, AckRequest ackRequest, String imei) {
logger.info("入网绑定查询接口imei=" + imei);
JoinBindResponse result = searchJoin(imei);
ackRequest.sendAckData(result);
}
/**
* 执行入网绑定接口
* @param client 客户端
* @param ackRequest 回执消息
* @param param 入网绑定参数
*/
@OnEvent(value = "doJoin")
public void onDoJoin(SocketIOClient client, AckRequest ackRequest, PosParam param) {
logger.info("执行入网绑定接口 start....");
BaseResponse result = postJoin(param);
ackRequest.sendAckData(result);
}
/**
* 绑定网点接口
* @param client 客户端
* @param ackRequest 回执消息
* @param param 绑定网点参数
*/
@OnEvent(value = "doBind")
public void onDoBind(SocketIOClient client, AckRequest ackRequest,BindParam param) {
logger.info("绑定网点接口 start....");
BaseResponse result = postBind(param);
ackRequest.sendAckData(result);
}
/**
* 报告地址接口
* @param client 客户端
* @param ackRequest 回执消息
* @param param 报告地址参数
*/
@OnEvent(value = "doReport")
public void onDoReport(SocketIOClient client, AckRequest ackRequest, ReportParam param) {
logger.info("报告地址接口 start....");
BaseResponse result = postReport(param);
ackRequest.sendAckData(result);
}
/**
* 版本检查接口
* @param client 客户端
* @param ackRequest 回执消息
* @param param 报告地址参数
*/
@OnEvent(value = "askVersion")
public void onAskVersion(SocketIOClient client, AckRequest ackRequest, VersionParam param) {
logger.info("版本检查接口 start....");
VersionResult result = apiService.selectPublishCount(param);;
ackRequest.sendAckData(result);
}
/*----------------------------------------下面是私有方法-------------------------------------*/
private JoinBindResponse searchJoin(String imei) {
JoinBindResponse result = new JoinBindResponse();
int posCount = apiService.selectCount(imei);
if (posCount > 0) {
// 如果入网了再去查询是否绑定了网点
int bindCount = apiService.selectBindCount(imei);
Pos pos = apiService.selectByImei(imei);
result.setPosState(pos.getPosState());
if (bindCount == 0) {
result.setSuccess(false);
result.setCode(2);
result.setMsg("已入网但尚未绑定网点");
} else {
result.setSuccess(true);
result.setCode(1);
result.setMsg("已入网并绑定了网点");
}
} else {
result.setSuccess(false);
result.setCode(3);
result.setMsg("未入网");
}
return result;
}
private BaseResponse postJoin(PosParam posParam) {
BaseResponse result = new BaseResponse();
// imei码约束检查
if (StringUtils.isEmpty(posParam.getImei()) || posParam.getImei().length() > 32) {
result.setSuccess(false);
result.setMsg("IMEI码长度不是1-32位入网失败。");
return result;
}
// 序列号SN约束检查
if (StringUtils.isEmpty(posParam.getSn()) || posParam.getSn().length() > 64) {
result.setSuccess(false);
result.setMsg("序列号长度不是1-64位入网失败。");
return result;
}
// 机具型号约束检查
if (StringUtils.isEmpty(posParam.getSeries()) || posParam.getSeries().length() > 32) {
result.setSuccess(false);
result.setMsg("机具型号不是1-32位入网失败。");
return result;
}
// Android版本约束检查
if (StringUtils.isEmpty(posParam.getAndroidVersion()) || posParam.getAndroidVersion().length() > 32) {
result.setSuccess(false);
result.setMsg("Android版本号不是1-32位入网失败。");
return result;
}
// 版本号约束检查
if (StringUtils.isEmpty(posParam.getVersion()) || posParam.getVersion().length() > 32) {
result.setSuccess(false);
result.setMsg("版本号不是1-32位入网失败。");
return result;
}
// 归属网点约束检查
if (StringUtils.isEmpty(posParam.getLocation()) || posParam.getLocation().length() > 64) {
result.setSuccess(false);
result.setMsg("归属网点不是1-64位入网失败。");
return result;
}
// 产权方约束检查
if (StringUtils.isEmpty(posParam.getOwner()) || posParam.getOwner().length() > 64) {
result.setSuccess(false);
result.setMsg("产权方不是1-64位入网失败。");
return result;
}
// 应用ID约束检查
if (StringUtils.isEmpty(posParam.getApplicationId()) || posParam.getApplicationId().length() > 64) {
result.setSuccess(false);
result.setMsg("应用ID不是1-64位入网失败。");
return result;
}
// 备注约束检查
if (StringUtils.isNotEmpty(posParam.getTips()) && posParam.getTips().length() > 255) {
result.setSuccess(false);
result.setMsg("备注超过255个字符入网失败。");
return result;
}
Pos pos = new Pos();
Date now = new Date();
pos.setJointime(now);
pos.setBindtime(now);
BeanUtils.copyProperties(posParam, pos);
// 根据applicationId设置归属项目ID
Project project = apiService.selectProjectByApplicationId(posParam.getApplicationId());
if (project == null) {
result.setSuccess(false);
result.setMsg("Application Id不正确入网失败。");
return result;
}
// 重复检查
int posCount = apiService.selectCount(posParam.getImei());
if (posCount > 0) {
result.setSuccess(false);
result.setMsg("入网失败,该机具之前已经入网了。");
return result;
}
// 插入一条新纪录
pos.setProjectId(project.getId());
int insert = apiService.insertPos(pos);
if (insert > 0) {
result.setSuccess(true);
result.setMsg("入网成功");
return result;
} else {
result.setSuccess(false);
result.setMsg("入网失败,请联系管理员。");
return result;
}
}
private BaseResponse postBind(BindParam bindParam) {
BaseResponse result = new BaseResponse();
// imei码约束检查
if (StringUtils.isEmpty(bindParam.getImei()) || bindParam.getImei().length() > 32) {
result.setSuccess(false);
result.setMsg("IMEI码长度不是1-32位绑定网点失败。");
return result;
}
// 归属网点约束检查
if (StringUtils.isEmpty(bindParam.getLocation()) || bindParam.getLocation().length() > 64) {
result.setSuccess(false);
result.setMsg("归属网点不是1-64位绑定网点失败。");
return result;
}
Pos pos = apiService.selectByImei(bindParam.getImei());
if (pos == null) {
result.setSuccess(false);
result.setMsg("该POS机尚未入网。");
return result;
}
Pos pos2 = apiService.selectBindByImei(bindParam.getImei());
if (pos2 != null) {
result.setSuccess(false);
result.setMsg("该POS机已经绑定了网点请先解绑。");
return result;
}
pos.setLocation(bindParam.getLocation());
Date now = new Date();
pos.setBindtime(now);
pos.setUpdatedTime(now);
apiService.bindLocation(pos);
result.setSuccess(true);
result.setMsg("绑定网点成功");
return result;
}
private BaseResponse postReport(ReportParam param) {
BaseResponse result = new BaseResponse();
// IMEI码约束检查
if (StringUtils.isEmpty(param.getImei()) || param.getImei().length() > 32) {
result.setSuccess(false);
result.setMsg("IMEI码不是1-32位报告地址接口失败。");
return result;
}
// 地址约束检查
if (StringUtils.isEmpty(param.getLocation()) || param.getLocation().length() > 255) {
result.setSuccess(false);
result.setMsg("地址不是1-255位报告地址接口失败。");
return result;
}
int r = apiService.report(param);
if (r > 0) {
result.setSuccess(true);
result.setMsg("报告地址成功");
} else {
result.setSuccess(false);
result.setMsg("该POS机还没有入网报告地址接口失败。");
}
return result;
}
}

View File

@ -0,0 +1,264 @@
package com.enzhico.jwt.service;
import com.baomidou.mybatisplus.mapper.Condition;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.enzhico.jwt.api.model.ReportParam;
import com.enzhico.jwt.api.model.VersionParam;
import com.enzhico.jwt.api.model.VersionResult;
import com.enzhico.jwt.common.dao.entity.Pos;
import com.enzhico.jwt.common.dao.entity.PosHistory;
import com.enzhico.jwt.common.dao.entity.PosMonitor;
import com.enzhico.jwt.common.dao.entity.Project;
import com.enzhico.jwt.common.dao.repository.PosHistoryMapper;
import com.enzhico.jwt.common.dao.repository.PosMapper;
import com.enzhico.jwt.common.dao.repository.PosMonitorMapper;
import com.enzhico.jwt.common.dao.repository.ProjectMapper;
import com.enzhico.jwt.common.util.CommonUtil;
import com.enzhico.jwt.config.properties.MyProperties;
import com.enzhico.jwt.dao.repository.ApiDao;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.UUID;
/**
* 专门用来服务对外接口用Service
*/
@Service
public class ApiService {
private static final Logger logger = LoggerFactory.getLogger(ApiService.class);
@Resource
private PosMapper posMapper;
@Resource
private PosHistoryMapper posHistoryMapper;
@Resource
private PosMonitorMapper posMonitorMapper;
@Resource
private ApiDao apiDao;
@Resource
private MyProperties myProperties;
@Resource
private ProjectMapper projectMapper;
@Resource
private SocketIOServer server;
/**
* 根据IMEI码查询POS机是否已经入网
*
* @param imei IMEI码
* @return 数量
*/
public int selectCount(String imei) {
return posMapper.selectCount(Condition.create().eq("imei", imei));
}
/**
* 根据IMEI码查找POS
*
* @param imei
* @return
*/
public Pos selectByImei(String imei) {
Pos p = new Pos();
p.setImei(imei);
return posMapper.selectOne(p);
}
/**
* 根据IMEI码查找绑定网点的POS
*
* @param imei
* @return
*/
public Pos selectBindByImei(String imei) {
Pos p = new Pos();
p.setImei(imei);
List<Pos> list = posMapper.selectList(Condition.create().eq("imei", imei).ne("location", "").isNotNull("location"));
return list != null && list.size() > 0 ? list.get(0) : null;
}
/**
* 根据IMEI码查询POS机是否绑定了网点
*
* @param imei IMEI码
* @return 绑定数量
*/
public int selectBindCount(String imei) {
return posMapper.selectCount(Condition.create().eq("imei", imei).isNotNull("location").ne("location", ""));
}
/**
* 更新机具信息
*
* @param pos
* @return
*/
public int bindLocation(Pos pos) {
// 先更新POS网点信息
posMapper.updateById(pos);
// 然后插入新的POS绑定历史记录
PosHistory posHistory = new PosHistory();
posHistory.setPosId(pos.getId());
posHistory.setLocation(pos.getLocation());
posHistory.setBindtime(pos.getBindtime());
return posHistoryMapper.insert(posHistory);
}
/**
* 执行POS机入网
*
* @param param 参数
* @return 结果
*/
public int insertPos(Pos param) {
param.setPosState(1);
// 插入一条pos记录
posMapper.insert(param);
// 插入一条历史记录
PosHistory posHistory = new PosHistory();
posHistory.setPosId(param.getId());
posHistory.setLocation(param.getLocation());
posHistory.setBindtime(new Date());
return posHistoryMapper.insert(posHistory);
}
/**
* 根据Application Id查询项目
*
* @param applicationId Application Id
* @return 项目
*/
public Project selectProjectByApplicationId(String applicationId) {
Project p = new Project();
p.setApplicationId(applicationId);
return projectMapper.selectOne(p);
}
/**
* 更新报告
*
* @param param 报告参数
* @return 结果
*/
public int report(ReportParam param) {
Pos p = new Pos();
p.setImei(param.getImei());
Pos pos = posMapper.selectOne(p);
if (pos == null) {
return 0;
}
Date now = new Date();
PosMonitor pmParam = new PosMonitor();
pmParam.setPosId(pos.getId());
PosMonitor posMonitor = posMonitorMapper.selectOne(pmParam);
if (posMonitor == null) {
PosMonitor plast = new PosMonitor();
plast.setPosId(pos.getId());
plast.setOnlineState(1);
plast.setReportTime(now);
plast.setReportLocation(param.getLocation());
return posMonitorMapper.insert(plast);
} else {
posMonitor.setOnlineState(1);
posMonitor.setReportTime(now);
posMonitor.setUpdatedTime(now);
posMonitor.setReportLocation(param.getLocation());
return posMonitorMapper.updateById(posMonitor);
}
}
/**
* Just Update monitor state
*
* @param param report param
* @param sessionId session id.
* @param state 1:在线 2:离线.
* @return result
*/
public int updateJustState(ReportParam param, String sessionId, Integer state) {
Pos p = new Pos();
p.setImei(param.getImei());
Pos pos = posMapper.selectOne(p);
if (pos == null) {
return 0;
}
Date now = new Date();
PosMonitor pmParam = new PosMonitor();
pmParam.setPosId(pos.getId());
PosMonitor posMonitor = posMonitorMapper.selectOne(pmParam);
if (posMonitor == null) {
PosMonitor plast = new PosMonitor();
plast.setPosId(pos.getId());
plast.setSessionId(sessionId);
plast.setOnlineState(state);
return posMonitorMapper.insert(plast);
} else {
posMonitor.setSessionId(sessionId);
posMonitor.setOnlineState(state);
posMonitor.setUpdatedTime(now);
return posMonitorMapper.updateById(posMonitor);
}
}
/**
* 根据imei码获取session id
*
* @param imei imei码
* @return sessionId
*/
public String selectSessionId(String imei) {
return apiDao.selectSessionId(imei);
}
/**
* 查询版本发布
* @param param 查询版本参数
* @return 结果
*/
public VersionResult selectPublishCount(VersionParam param) {
VersionResult r = apiDao.selectPublishCount(param);
if (r != null && CommonUtil.isNewer(r.getVersion(), param.getVersion())) {
r.setFindNew(true);
r.setDownloadUrl(myProperties.getApkUrlPrefix() + r.getAppName() + "_" + r.getVersion() + ".apk");
} else {
r = new VersionResult();
r.setFindNew(false);
}
return r;
}
/**
* 给某个POS机推送网点解除绑定消息
* @param imei imei码
* @param location 解除的网点
* @return error msg
*/
public String sendUnbind(String imei, String location) {
logger.info("开始给POS机推送解绑消息");
// 先获取session id
String sessionId = selectSessionId(imei);
if (StringUtils.isEmpty(sessionId)) {
logger.error("找不到可用的sessionId");
return "找不到可用的sessionId";
}
SocketIOClient targetClient = this.server.getClient(UUID.fromString(sessionId));
if (targetClient == null) {
logger.error("sessionId=" + sessionId + "在server中获取不到client");
return "sessionId=" + sessionId + "在server中获取不到client";
}
targetClient.sendEvent("unbind", location);
return null;
}
}

View File

@ -0,0 +1,204 @@
package com.enzhico.jwt.service;
import com.baomidou.mybatisplus.mapper.Condition;
import com.baomidou.mybatisplus.plugins.Page;
import com.enzhico.jwt.common.dao.entity.Manager;
import com.enzhico.jwt.common.dao.entity.Project;
import com.enzhico.jwt.common.dao.entity.ProjectUser;
import com.enzhico.jwt.common.dao.repository.ProjectMapper;
import com.enzhico.jwt.common.dao.repository.ProjectUserMapper;
import com.enzhico.jwt.dao.entity.ManagerInfo;
import com.enzhico.jwt.dao.entity.SearchUser;
import com.enzhico.jwt.dao.repository.ManagerInfoDao;
import com.enzhico.jwt.exception.ForbiddenUserException;
import com.enzhico.jwt.shiro.ShiroKit;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
/**
* 后台用户管理
*/
@Service
public class ManagerInfoService {
@Resource
private ManagerInfoDao managerInfoDao;
@Resource
private ProjectMapper projectMapper;
@Resource
private ProjectUserMapper projectUserMapper;
/**
* 通过名称查找用户
*
* @param username
* @return
*/
public ManagerInfo findByUsername(String username) {
ManagerInfo managerInfo = managerInfoDao.findByUsername(username);
if (managerInfo == null) {
throw new UnknownAccountException();
}
if (managerInfo.getState() == 2) {
throw new ForbiddenUserException();
}
if (managerInfo.getPidsList() == null) {
managerInfo.setPidsList(Collections.singletonList(0));
} else if (managerInfo.getPidsList().size() == 0) {
managerInfo.getPidsList().add(0);
}
return managerInfo;
}
/**
* 检查用户名重复
*
* @param username
* @return
*/
public int checkUsername(String username) {
return managerInfoDao.selectCount(Condition.create().eq("username", username));
}
/**
* 通过ID查找用户
*
* @param id
* @return
*/
public ManagerInfo selectUser(Integer id) {
ManagerInfo managerInfo = managerInfoDao.selectUser(id);
List<Integer> li = new ArrayList<>();
if (StringUtils.isNotEmpty(managerInfo.getPids())) {
for (String s : managerInfo.getPids().split(",")) {
li.add(Integer.parseInt(s));
}
}
managerInfo.setPidsList(li);
return managerInfo;
}
/**
* 所有项目列表
*
* @return
*/
public List<Project> allProjects() {
return projectMapper.selectList(null);
}
/**
* 执行添加用户
*
* @param manager
* @return
*/
public int addUser(ManagerInfo manager) {
String salt = ShiroKit.getRandomSalt(16);
//进行散列
SimpleHash hash = new SimpleHash("md5", "12345678", manager.getUsername() + salt, 2);
manager.setSalt(salt);
manager.setPassword(hash.toHex());
managerInfoDao.insert(manager);
// 更新项目用户关联表
if (StringUtils.isNotEmpty(manager.getPids())) {
for (String pid : manager.getPids().split(",")) {
ProjectUser projectUser = new ProjectUser();
projectUser.setUserId(manager.getId());
projectUser.setProjectId(Integer.valueOf(pid));
projectUserMapper.insert(projectUser);
}
}
return 1;
}
/**
* 执行更新用户
*
* @param manager
* @return
*/
public int editUser(ManagerInfo manager) {
managerInfoDao.updateById(manager);
// 更新项目用户关联表
if (StringUtils.isNotEmpty(manager.getPids())) {
// 先把该用户的项目关联删了
projectUserMapper.delete(Condition.create().eq("user_id", manager.getId()));
// 然后插入选择的项目关系
for (String pid : manager.getPids().split(",")) {
ProjectUser projectUser = new ProjectUser();
projectUser.setUserId(manager.getId());
projectUser.setProjectId(Integer.valueOf(pid));
projectUserMapper.insert(projectUser);
}
}
return 1;
}
/**
* 执行重置密码
*
* @param id 用户ID
* @return
*/
public int resetPassword(Integer id, String username) {
String salt = ShiroKit.getRandomSalt(16);
//进行散列
SimpleHash hash = new SimpleHash("md5", "12345678", username + salt, 2);
String password = hash.toHex();
Manager p = new Manager();
p.setId(id);
p.setPassword(password);
p.setSalt(salt);
p.setUpdatedTime(new Date());
return managerInfoDao.updateById(p);
}
/**
* 执行删除用户
*
* @param id 用户ID
* @return
*/
public int deleteUer(Integer id) {
return managerInfoDao.deleteById(id);
}
/**
* 修改密码
*
* @param username 用户名
* @param password 加密后的密码
* @return result
*/
public int updatePassword(String username, String password) {
Manager v = new Manager();
v.setPassword(password);
v.setUpdatedTime(new Date());
return managerInfoDao.update(v, Condition.create().eq("username", username));
}
/**
* 分页查询用户
*
* @param page
* @param searchUser
* @return
*/
public List<ManagerInfo> searchUsers(Page<ManagerInfo> page, SearchUser searchUser) {
List<ManagerInfo> list = managerInfoDao.selectUsers(page, searchUser);
for (ManagerInfo managerInfo : list) {
managerInfo.buildTable();
}
return list;
}
}

View File

@ -0,0 +1,94 @@
package com.enzhico.jwt.shiro;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class JWTFilter extends BasicHttpAuthenticationFilter {
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
/**
* 判断用户是否想要登入
* 检测header里面是否包含Authorization字段即可
*/
@Override
protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
HttpServletRequest req = (HttpServletRequest) request;
String authorization = req.getHeader("Authorization");
return authorization != null;
}
/**
*
*/
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authorization = httpServletRequest.getHeader("Authorization");
JWTToken token = new JWTToken(authorization);
// 提交给realm进行登入如果错误他会抛出异常并被捕获
getSubject(request, response).login(token);
// 如果没有抛出异常则代表登入成功返回true
return true;
}
/**
* 这里我们详细说明下为什么最终返回的都是true即允许访问
* 例如我们提供一个地址 GET /article
* 登入用户和游客看到的内容是不同的
* 如果在这里返回了false请求会被直接拦截用户看不到任何东西
* 所以我们在这里返回trueController中可以通过 subject.isAuthenticated() 来判断用户是否登入
* 如果有些资源只有登入用户才能访问我们只需要在方法上面加上 @RequiresAuthentication 注解即可
* 但是这样做有一个缺点就是不能够对GET,POST等请求进行分别过滤鉴权(因为我们重写了官方的方法)但实际上对应用影响不大
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if (isLoginAttempt(request, response)) {
try {
executeLogin(request, response);
} catch (Exception e) {
response401(request, response);
}
}
return true;
}
/**
* 对跨域提供支持
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
// 跨域时会首先发送一个option请求这里我们给option请求直接返回正常状态
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
return super.preHandle(request, response);
}
/**
* 将非法请求跳转到 /401
*/
private void response401(ServletRequest req, ServletResponse resp) {
try {
HttpServletResponse httpServletResponse = (HttpServletResponse) resp;
httpServletResponse.sendRedirect("/401");
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
}

View File

@ -0,0 +1,23 @@
package com.enzhico.jwt.shiro;
import org.apache.shiro.authc.AuthenticationToken;
public class JWTToken implements AuthenticationToken {
// 密钥
private String token;
public JWTToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}

View File

@ -0,0 +1,121 @@
package com.enzhico.jwt.shiro;
import com.enzhico.jwt.common.dao.entity.Permission;
import com.enzhico.jwt.common.util.JWTUtil;
import com.enzhico.jwt.dao.entity.ManagerInfo;
import com.enzhico.jwt.dao.entity.SysRole;
import com.enzhico.jwt.service.ManagerInfoService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Description : 身份校验核心类
*/
public class MyShiroRealm extends AuthorizingRealm {
private static final Logger _logger = LoggerFactory.getLogger(MyShiroRealm.class);
@Autowired
ManagerInfoService managerInfoService;
/**
* JWT签名密钥
*/
public static final String SECRET = "9281e268b77b7c439a20b46fd1483b9a";
/**
* 必须重写此方法不然Shiro会报错
*/
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JWTToken;
}
/**
* 认证信息(身份验证)
* Authentication 是用来验证用户身份
*
* @param auth
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth)
throws AuthenticationException {
_logger.info("MyShiroRealm.doGetAuthenticationInfo()");
String token = (String) auth.getCredentials();
// 解密获得username用于和数据库进行对比
String username = JWTUtil.getUsername(token);
if (username == null) {
throw new AuthenticationException("token invalid");
}
//通过username从数据库中查找 ManagerInfo对象
//实际项目中这里可以根据实际情况做缓存如果不做Shiro自己也是有时间间隔机制2分钟内不会重复执行该方法
ManagerInfo managerInfo = managerInfoService.findByUsername(username);
if (managerInfo == null) {
throw new AuthenticationException("用户不存在!");
}
if (!JWTUtil.verify(token, username, managerInfo.getPassword())) {
throw new AuthenticationException("Token认证失败");
}
return new SimpleAuthenticationInfo(token, token, "my_realm");
}
/**
* 此方法调用hasRole,hasPermission的时候才会进行回调.
* <p>
* 权限信息.(授权):
* 1如果用户正常退出缓存自动清空
* 2如果用户非正常退出缓存自动清空
* 3如果我们修改了用户的权限而用户不退出系统修改的权限无法立即生效
* 需要手动编程进行实现放在service进行调用
* 在权限修改后调用realm中的方法realm已经由spring管理所以从spring中获取realm实例调用clearCached方法
* :Authorization 是授权访问控制用于对用户进行的操作授权证明该用户是否允许进行当前操作如访问某个链接某个资源文件等
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
/*
* 当没有使用缓存的时候不断刷新页面的话这个代码会不断执行
* 当其实没有必要每次都重新设置权限信息所以我们需要放到缓存中进行管理
* 当放到缓存中时这样的话doGetAuthorizationInfo就只会执行一次了
* 缓存过期之后会再次执行
*/
_logger.info("权限配置-->MyShiroRealm.doGetAuthorizationInfo()");
String username = JWTUtil.getUsername(principals.toString());
// 下面的可以使用缓存提升速度
ManagerInfo managerInfo = managerInfoService.findByUsername(username);
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//设置相应角色的权限信息
for (SysRole role : managerInfo.getRoles()) {
//设置角色
authorizationInfo.addRole(role.getRole());
for (Permission p : role.getPermissions()) {
//设置权限
authorizationInfo.addStringPermission(p.getPermission());
}
}
return authorizationInfo;
}
}

View File

@ -0,0 +1,187 @@
/**
* Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.enzhico.jwt.shiro;
import com.enzhico.jwt.dao.entity.ManagerInfo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
/**
* shiro工具类
*
* @author dafei, Chill Zhuang
*/
public class ShiroKit {
private static final String NAMES_DELIMETER = ",";
/**
* 散列算法
*/
public final static String HASH_ALGORITHM_NAME = "MD5";
/**
* 循环次数
*/
public final static int HASH_ITERATIONS = 2;
/**
* shiro密码加密工具类
*
* @param credentials 密码
* @param saltSource 密码盐
* @return
*/
public static String md5(String credentials, String saltSource) {
return new SimpleHash(HASH_ALGORITHM_NAME, credentials, saltSource, HASH_ITERATIONS).toHex();
}
/**
* 获取随机盐值
*
* @param length 字节长度一个字节2位16进制数表示
* @return
*/
public static String getRandomSalt(int length) {
return new SecureRandomNumberGenerator().nextBytes(length).toHex();
}
/**
* 获取当前 Subject
*
* @return Subject
*/
public static Subject getSubject() {
return SecurityUtils.getSubject();
}
/**
* 验证当前用户是否属于该角色,使用时与lacksRole 搭配使用
*
* @param roleName 角色名
* @return 属于该角色true否则false
*/
public static boolean hasRole(String roleName) {
return getSubject() != null && roleName != null
&& roleName.length() > 0 && getSubject().hasRole(roleName);
}
/**
* 与hasRole标签逻辑相反当用户不属于该角色时验证通过
*
* @param roleName 角色名
* @return 不属于该角色true否则false
*/
public static boolean lacksRole(String roleName) {
return !hasRole(roleName);
}
/**
* 验证当前用户是否属于以下任意一个角色
*
* @param roleNames 角色列表
* @return 属于:true,否则false
*/
public static boolean hasAnyRoles(String roleNames) {
boolean hasAnyRole = false;
Subject subject = getSubject();
if (subject != null && roleNames != null && roleNames.length() > 0) {
for (String role : roleNames.split(NAMES_DELIMETER)) {
if (subject.hasRole(role.trim())) {
hasAnyRole = true;
break;
}
}
}
return hasAnyRole;
}
/**
* 验证当前用户是否拥有指定权限,使用时与lacksPermission 搭配使用
*
* @param permission 权限名
* @return 拥有权限true否则false
*/
public static boolean hasPermission(String permission) {
return getSubject() != null && permission != null
&& permission.length() > 0
&& getSubject().isPermitted(permission);
}
/**
* 与hasPermission标签逻辑相反当前用户没有制定权限时验证通过
*
* @param permission 权限名
* @return 拥有权限true否则false
*/
public static boolean lacksPermission(String permission) {
return !hasPermission(permission);
}
/**
* 已认证通过的用户不包含已记住的用户这是与user标签的区别所在与notAuthenticated搭配使用
*
* @return 通过身份验证true否则false
*/
public static boolean isAuthenticated() {
return getSubject() != null && getSubject().isAuthenticated();
}
/**
* 未认证通过用户与authenticated标签相对应与guest标签的区别是该标签包含已记住用户
*
* @return 没有通过身份验证true否则false
*/
public static boolean notAuthenticated() {
return !isAuthenticated();
}
/**
* 认证通过或已记住的用户与guset搭配使用
*
* @return 用户true否则 false
*/
public static boolean isUser() {
return getSubject() != null && getSubject().getPrincipal() != null;
}
/**
* 验证当前用户是否为访客即未认证包含未记住的用户用user搭配使用
*
* @return 访客true否则false
*/
public static boolean isGuest() {
return !isUser();
}
/**
* 输出当前用户信息通常为登录帐号信息
*
* @return 当前用户信息
*/
public static String principal() {
if (getSubject() != null) {
Object principal = getSubject().getPrincipal();
return principal.toString();
}
return "";
}
}

View File

@ -0,0 +1,97 @@
##########################################################
################## 所有profile共有的配置 #################
##########################################################
################### 自定义项目配置 ###################
enzhico:
socket-port: 9096 #socket端口
ping-interval: 60000 #Ping消息间隔毫秒
ping-timeout: 180000 #Ping消息超时时间毫秒
################### 项目启动端口 ###################
server.port: 9095
################### spring配置 ###################
spring:
profiles:
active: dev
http:
multipart:
max-request-size: 100MB #最大请求大小
max-file-size: 100MB #最大文件大小
################### mybatis-plus配置 ###################
mybatis-plus:
mapper-locations: classpath*:com/enzhico/jwt/dao/repository/mapping/*.xml
typeAliasesPackage: >
com.enzhico.jwt.api.model,
com.enzhico.jwt.dao.entity,
com.enzhico.jwt.common.dao.entity
global-config:
id-type: 0 # 0:数据库ID自增 1:用户输入id 2:全局唯一id(IdWorker) 3:全局唯一ID(uuid)
db-column-underline: false
refresh-mapper: true
configuration:
map-underscore-to-camel-case: true
cache-enabled: true #配置的缓存的全局开关
lazyLoadingEnabled: true #延时加载的开关
multipleResultSetsEnabled: true #开启的话,延时加载一个属性时会加载该对象全部属性,否则按需加载属性
################### spring security配置 ###################
security:
ignored: /static/**
logging:
level:
org.springframework.web.servlet: ERROR
---
#####################################################################
######################## 开发环境profile ##########################
#####################################################################
spring:
profiles: dev
datasource:
url: jdbc:mysql://123.207.66.156:3306/pos?useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8
username: root
password: _EnZhi123
thymeleaf:
cache: false
################### 自定义项目配置 ###################
enzhico:
apk-url-prefix: http://enzhico.net/files/ #APK文件访问URL前缀
logging:
level:
ROOT: INFO
com:
enzhico: DEBUG
file: E:/logs/pos-api.log
---
#####################################################################
######################## 测试环境profile ##########################
#####################################################################
spring:
profiles: test
datasource:
url: jdbc:mysql://123.207.66.156:3306/pos?useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8
username: root
password: _EnZhi123
thymeleaf:
cache: false
################### 自定义项目配置 ###################
enzhico:
apk-url-prefix: https://show.enzhico.net/files/ #APK文件访问URL前缀
logging:
level:
ROOT: INFO
com:
enzhico: DEBUG
file: /var/logs/app-manage-api.log

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false" monitoring="autodetect"
dynamicConfig="true">
<diskStore path="java.io.tmpdir/ehcache"/>
<defaultCache
maxElementsInMemory="50000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="true"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
<cache name="authorizationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="false"
statistics="true">
</cache>
<cache name="authenticationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="false"
statistics="true">
</cache>
<cache name="org.apache.shiro.realm.text.PropertiesRealm-0-accounts"
maxElementsInMemory="1000"
eternal="true"
overflowToDisk="true"/>
</ehcache>
<!--
maxElementsInMemory="10000" //Cache中最多允许保存的数据对象的数量
external="false" //缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期
timeToLiveSeconds="3600" //缓存的存活时间,从开始创建的时间算起
timeToIdleSeconds="3600" //多长时间不访问该缓存那么ehcache 就会清除该缓存
这两个参数很容易误解看文档根本没用我仔细分析了ehcache的代码。结论如下
1、timeToLiveSeconds的定义是以创建时间为基准开始计算的超时时长
2、timeToIdleSeconds的定义是在创建时间和最近访问时间中取出离现在最近的时间作为基准计算的超时时长
3、如果仅设置了timeToLiveSeconds则该对象的超时时间=创建时间+timeToLiveSeconds假设为A
4、如果没设置timeToLiveSeconds则该对象的超时时间=min(创建时间,最近访问时间)+timeToIdleSeconds假设为B
5、如果两者都设置了则取出A、B最少的值即min(A,B),表示只要有一个超时成立即算超时。
overflowToDisk="true" //内存不足时,是否启用磁盘缓存
diskSpoolBufferSizeMB //设置DiskStore磁盘缓存的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
maxElementsOnDisk //硬盘最大缓存个数
diskPersistent //是否缓存虚拟机重启期数据The default value is false
diskExpiryThreadIntervalSeconds //磁盘失效线程运行时间间隔默认是120秒。
memoryStoreEvictionPolicy="LRU" //当达到maxElementsInMemory限制时Ehcache将会根据指定的策略去清理内存。默认策略是LRU最近最少使用。你可以设置为FIFO先进先出或是LFU较少使用
clearOnFlush //内存数量最大时是否清除
maxEntriesLocalHeap="0"
maxEntriesLocalDisk="1000"
-->

View File

@ -0,0 +1,314 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
通过一个schema.sql来生成标准表结构的Domain和基础Mapper
基于mybatis-plus库使用
使用方法2种
1. python generate_mapper.py src_base_dir domain_package mapper_package schema_name author
2. 配置好下面的参数后直接运行此文件 python generate_mapper.py
参数
1. src_base_dir 源码基础路径
2. domain_package domain类的包名
3. mapper_package mapper类的包名
4. schema_name schema sql文件的绝对路径
5. author 源代码的作者熊能
"""
###################################下面的参数你来指定###########################
src_base_dir = r'E:\enzhico\app-manage\src\main\java'
domain_package = r'com.enzhico.jwt.common.dao.entity'
mapper_package = r'com.enzhico.jwt.common.dao.repository'
schema_name = r'E:\enzhico\app-manage\src\main\resources\sql\schema.sql'
author = r'熊能'
TODAY_STR = '2018/01/02'
###############################################################################
import sys
import os
import datetime
import shutil
# 基类功能列
BASE_FIELS = {}
# MySQL type to java type
MYSQL_TYPE_MAP = {
'BIT(1)': ('Boolean',)
, 'BIT': ('byte[]',)
, 'TINYINT': ('Integer',)
, 'BOOLEAN': ('Boolean',)
, 'BOOL': ('Boolean',)
, 'SMALLINT': ('Integer',)
, 'MEDIUMINT': ('Integer',)
, 'INT': ('Integer',)
, 'INTEGER': ('Integer',)
, 'BIGINT': ('Long',)
, 'FLOAT': ('Float',)
, 'DOUBLE': ('Double',)
, 'DECIMAL': ('BigDecimal', 'java.math.BigDecimal')
, 'DATE': ('Date', 'java.util.Date')
, 'DATETIME': ('Date', 'java.util.Date')
, 'TIMESTAMP': ('Date', 'java.util.Date')
, 'TIME': ('Date', 'java.util.Date')
, 'CHAR': ('String ',)
, 'VARCHAR': ('String',)
, 'BINARY': ('byte[]',)
, 'VARBINARY': ('byte[]',)
, 'TINYBLOB': ('byte[]',)
, 'TINYTEXT': ('String',)
, 'BLOB': ('byte[]',)
, 'TEXT': ('String',)
, 'MEDIUMBLOB': ('byte[]',)
, 'MEDIUMTEXT': ('String',)
, 'LONGBLOB': ('byte[]',)
, 'LONGTEXT': ('String',)
, 'ENUM': ('String',)
, 'SET': ('String',)
, 'bit(1)': ('Boolean',)
, 'bit': ('byte[]',)
, 'tinyint': ('Integer',)
, 'boolean': ('Boolean',)
, 'bool': ('Boolean',)
, 'smallint': ('Integer',)
, 'mediumint': ('Integer',)
, 'int': ('Integer',)
, 'integer': ('Integer',)
, 'bigint': ('Long',)
, 'float': ('Float',)
, 'double': ('Double',)
, 'decimal': ('BigDecimal', 'java.math.BigDecimal')
, 'date': ('Date', 'java.util.Date')
, 'datetime': ('Date', 'java.util.Date')
, 'timestamp': ('Date', 'java.util.Date')
, 'time': ('Date', 'java.util.Date')
, 'char': ('String ',)
, 'varchar': ('String',)
, 'binary': ('byte[]',)
, 'varbinary': ('byte[]',)
, 'tinyblob': ('byte[]',)
, 'tinytext': ('String',)
, 'blob': ('byte[]',)
, 'text': ('String',)
, 'mediumblob': ('byte[]',)
, 'mediumtext': ('String',)
, 'longblob': ('byte[]',)
, 'longtext': ('String',)
, 'enum': ('String',)
, 'set': ('String',)
}
def camel_to_underline(camel_format):
"""
驼峰命名格式转下划线命名格式
"""
return ''.join([s if s.islower() else '_' + s.lower() for s in camel_format])[1:]
def underline_to_camel(underline_format, is_field=False):
"""
下划线命名格式驼峰命名格式
"""
try:
result = ''.join([s.capitalize() for s in underline_format.split('_')])
except:
print(underline_format + "...error...")
return result[0].lower() + result[1:] if is_field else result
def load_schema(filename):
"""先加载schema.sql文件来获取所有建表语句"""
result = []
with open(filename, encoding='utf-8') as sqlfile:
each_table = [] # 每张表定义
for line in sqlfile:
linestrip = line.strip()
if not linestrip or linestrip.startswith("#") \
or linestrip.startswith("INDEX") or linestrip.startswith("ALTER TABLE"):
continue
line = line.replace("`", "")
if line.startswith('--'):
temp_comment = line.split('--')[1].strip()
elif 'DROP TABLE' in line:
each_table.insert(0, temp_comment)
each_table.insert(1, line.strip().split()[-1][:-1])
elif ' COMMENT ' in line and 'ENGINE=' not in line:
col_arr = line.split()
col_name = col_arr[0]
col_type = col_arr[1]
if 'PRIMARY KEY' in line or 'NOT NULL' in line:
col_null = 'NOT NULL'
else:
col_null = ''
col_remark = line.split(' COMMENT ')
cr = col_remark[-1].strip().replace("'", "")
each_table.append((col_name, col_type, col_null, cr[:-1] if cr.endswith(',') else cr))
elif 'ENGINE=' in line:
# 单个表定义结束
result.append(list(each_table))
each_table.clear()
return result
def write_beans(src_base_dir, domain_package, mapper_package, schema_name, author):
beans_dir = os.path.join(src_base_dir, domain_package.replace('.', os.sep))
mapper_dir = os.path.join(src_base_dir, mapper_package.replace('.', os.sep))
if not os.path.exists(beans_dir):
os.makedirs(beans_dir)
if not os.path.exists(mapper_dir):
os.makedirs(mapper_dir)
shutil.rmtree(beans_dir)
os.mkdir(beans_dir)
shutil.rmtree(mapper_dir)
os.mkdir(mapper_dir)
domain_package_with_semicolon = domain_package + ";"
mapper_package_with_semicolon = mapper_package + ";"
# 今日格式化字符串
# today_today = datetime.datetime.now().strftime('%Y/%m/%d')
today_today = TODAY_STR
today_str = ' * @since {}'.format(today_today)
table_data = load_schema(schema_name)
# 然后开始对每个表生成一个Domain类
for table in table_data:
table_name_comment = table[0]
table_name_real = table[1]
class_name = underline_to_camel(table_name_real[2:])
lines = []
lines.append('package ' + domain_package_with_semicolon)
lines.append('\n')
lines.append('import com.baomidou.mybatisplus.annotations.TableName;')
lines.append('import com.baomidou.mybatisplus.enums.IdType;')
lines.append('import com.baomidou.mybatisplus.annotations.TableId;')
lines.append('import com.baomidou.mybatisplus.activerecord.Model;')
lines.append('import java.io.Serializable;')
lines.append('\n')
lines.append('/**')
lines.append(' * ' + table_name_comment)
lines.append(' *')
lines.append(' * @author {}'.format(author))
lines.append(' * @version 1.0')
lines.append(today_str)
lines.append(' */')
lines.append('@TableName(value = "{}")'.format(table_name_real))
lines.append('public class {} extends Model<{}> {{'.format(class_name, class_name))
lines.append('\n')
lines.append('private static final long serialVersionUID = 1L;')
lines.append('\n')
lines_fields = []
lines_methods = []
other_import = set()
field_name_list = []
for each_column in table[2:]:
# 列名
column_name = each_column[0]
if column_name in BASE_FIELS:
continue
field_name = underline_to_camel(column_name, is_field=True)
field_name_list.append(field_name)
field_name_method = underline_to_camel(column_name)
# 类型
ctype = each_column[1]
java_type_t = MYSQL_TYPE_MAP[ctype.split('(')[0] if ctype != 'BIT(1)' else ctype]
java_type = java_type_t[0]
import_str = 'import {};'.format(java_type_t[1]) if len(java_type_t) > 1 else None
# 空值约束
column_null = each_column[2]
# 字段生成
column_comment = each_column[3]
lines_fields.append(' /**')
lines_fields.append(' * {}'.format(column_comment))
lines_fields.append(' */')
if column_name == 'id':
lines_fields.append(' @TableId(value="id", type= IdType.AUTO)')
lines_fields.append(' private {} {};'.format(java_type, field_name))
if import_str:
other_import.add(import_str)
# get方法生成
lines_methods.append(' /**')
lines_methods.append(' * 获取 {}.'.format(column_comment))
lines_methods.append(' *')
lines_methods.append(' * @return {}.'.format(column_comment))
lines_methods.append(' */')
lines_methods.append(' public {} get{}() {{'.format(java_type, field_name_method))
lines_methods.append(' return {};'.format(field_name))
lines_methods.append(' }')
lines_methods.append('\n')
# set方法生成
lines_methods.append(' /**')
lines_methods.append(' * 设置 {}.'.format(column_comment))
lines_methods.append(' *')
lines_methods.append(' * @param {} {}.'.format(field_name, column_comment))
lines_methods.append(' */')
lines_methods.append(' public void set{}({} {}) {{'.format(
field_name_method, java_type, field_name))
lines_methods.append(' this.{} = {};'.format(field_name, field_name))
lines_methods.append(' }')
lines_methods.append('\n')
for each_other in sorted(other_import):
lines.insert(2, each_other)
lines.extend(lines_fields)
lines.append('\n')
lines.extend(lines_methods)
# 最后加上pkVal()实现
lines.append(' @Override')
lines.append(' protected Serializable pkVal() {')
lines.append(' return this.id;')
lines.append(' }')
lines.append('\n')
lines.append('}')
# 加上换行符
lines = [line + "\n" if line != '\n' else line for line in lines]
# 开始写java源文件
java_file = class_name + '.java'
with open(os.path.join(beans_dir, java_file), mode='w', encoding='utf-8') as jf:
jf.writelines(lines)
# 然后开始对每个表生成一个Mapper类
for table in table_data:
table_name_comment = table[0]
table_name_real = table[1]
class_name = underline_to_camel(table_name_real[2:])
lines = []
lines.append('package ' + mapper_package_with_semicolon)
lines.append('\n')
lines.append('import {}.{};'.format(domain_package, class_name))
lines.append('import com.baomidou.mybatisplus.mapper.BaseMapper;')
lines.append('\n')
lines.append('/**')
lines.append(' * ' + table_name_comment + " Mapper")
lines.append(' *')
lines.append(' * @author {}'.format(author))
lines.append(' * @version 1.0')
lines.append(today_str)
lines.append(' */')
lines.append('public interface {0}Mapper extends BaseMapper<{0}> {{'.format(class_name))
lines.append('\n')
lines.append('}')
lines = [line + "\n" if line != '\n' else line for line in lines]
# 开始写mapper源文件
with open(os.path.join(mapper_dir, '{}Mapper.java'.format(class_name)), mode='w', encoding='utf-8') as jf:
jf.writelines(lines)
print('successful...')
pass
if __name__ == '__main__':
if len(sys.argv) > 4:
src_base_dir = sys.argv[1]
domain_package = sys.argv[2]
mapper_package = sys.argv[3]
schema_name = sys.argv[4]
author = sys.argv[5]
write_beans(src_base_dir, domain_package, mapper_package, schema_name, author)

View File

@ -0,0 +1,177 @@
# -------------------------------------以下业务表开始-------------------------------------------
-- 项目表
DROP TABLE IF EXISTS `t_project`;
CREATE TABLE `t_project` (
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`name` VARCHAR(64) DEFAULT '' COMMENT '项目名称',
`application_id` VARCHAR(64) DEFAULT '' COMMENT '应用编号',
`icon` VARCHAR(64) DEFAULT '' COMMENT '项目图片',
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='项目表';
-- 项目用户关联表
DROP TABLE IF EXISTS `t_project_user`;
CREATE TABLE `t_project_user` (
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`user_id` INT(11) NOT NULL COMMENT '用户ID',
`project_id` INT(11) NOT NULL COMMENT '项目ID',
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='项目用户关联表';
-- POS机表
DROP TABLE IF EXISTS `t_pos`;
CREATE TABLE `t_pos` (
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`imei` VARCHAR(32) DEFAULT '' COMMENT '机具IMEI码',
`sn` VARCHAR(64) DEFAULT '' COMMENT '序列号(SN)',
`series` VARCHAR(32) DEFAULT '' COMMENT '机具型号',
`android_version` VARCHAR(32) DEFAULT '' COMMENT 'Android版本',
`version` VARCHAR(64) DEFAULT '' COMMENT '版本号',
`location` VARCHAR(64) DEFAULT '' COMMENT '归属网点',
`project_id` INT(11) DEFAULT 0 COMMENT '归属项目ID',
`jointime` DATETIME COMMENT '入网时间',
`bindtime` DATETIME COMMENT '绑定时间',
`owner` VARCHAR(64) DEFAULT '' COMMENT '产权方',
`tips` VARCHAR(255) DEFAULT '' COMMENT '备注',
`pos_state` TINYINT(1) COMMENT '机具状态: 1:正常 2:故障 3:维修中(返厂) 4:已禁用(丢失) 5:已停用(回收)',
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='POS机表';
-- POS机监控表
DROP TABLE IF EXISTS `t_pos_monitor`;
CREATE TABLE `t_pos_monitor` (
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`pos_id` INT(11) COMMENT 'POS机ID',
`session_id` VARCHAR(64) DEFAULT '' COMMENT 'Socket会话ID',
`report_time` DATETIME COMMENT '最近一次报告时间',
`report_location` VARCHAR(255) DEFAULT '' COMMENT '最近一次报告地址',
`online_state` TINYINT(1) COMMENT '在线状态: 1:在线 2:离线',
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='POS机历史归属表';
-- POS机历史归属表
DROP TABLE IF EXISTS `t_pos_history`;
CREATE TABLE `t_pos_history` (
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`pos_id` INT(11) COMMENT 'POS机ID',
`location` VARCHAR(64) DEFAULT '' COMMENT '归属网点',
`bindtime` DATETIME COMMENT '绑定时间',
`unbindtime` DATETIME COMMENT '解绑时间',
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='POS机历史归属表';
-- APP表
DROP TABLE IF EXISTS `t_app`;
CREATE TABLE `t_app` (
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`application_id` VARCHAR(64) DEFAULT '' COMMENT '应用编号',
`name` VARCHAR(32) DEFAULT '' COMMENT '应用名称',
`version` VARCHAR(8) DEFAULT '' COMMENT '版本号',
`tips` VARCHAR(255) DEFAULT '' COMMENT '版本说明',
`project_id` INT(11) DEFAULT 0 COMMENT '归属项目ID',
`publishtime` DATETIME COMMENT '发布时间',
`publish_range` TINYINT(1) COMMENT '发布范围 1:全网发布 2:灰度发布',
`operator_id` INT(11) COMMENT '操作者ID',
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='APP表';
-- APP发布表
DROP TABLE IF EXISTS `t_app_publish`;
CREATE TABLE `t_app_publish` (
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`app_id` INT(11) COMMENT 'APP主键',
`pos_id` INT(11) COMMENT 'POS主键',
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='APP发布表';
# -------------------------------------以下用户管理表开始-------------------------------------------
-- 后台管理用户表
DROP TABLE IF EXISTS `t_manager`;
CREATE TABLE `t_manager` (
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`username` VARCHAR(32) NOT NULL COMMENT '账号',
`name` VARCHAR(16) DEFAULT '' COMMENT '名字',
`password` VARCHAR(128) DEFAULT '' COMMENT '密码',
`salt` VARCHAR(64) DEFAULT '' COMMENT 'md5密码盐',
`phone` VARCHAR(32) DEFAULT '' COMMENT '联系电话',
`tips` VARCHAR(255) COMMENT '备注',
`state` TINYINT(1) DEFAULT 1 COMMENT '状态 1:正常 2:禁用',
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='后台管理用户表';
INSERT INTO `t_manager` VALUES (1,'admin','大Boss','8e801b56148cd65c8c9af9253794f48c','26edbd50d8ee398294f31b30e0803298', '17890908889', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');
INSERT INTO `t_manager` VALUES (2,'aix','张三','2412d3972722eb186f69a8f4011fbd48','20545a7eaea0241ddf6652a3f9a4ae24', '17859569358', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');
-- 角色表
DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role` (
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`role` VARCHAR(16) DEFAULT '' COMMENT '角色名称',
`description` VARCHAR(255) DEFAULT '' COMMENT '角色说明',
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='角色表';
INSERT INTO `t_role` VALUES (1,'admin','超级管理员', '2017-12-12 09:46:12', '2017-12-12 09:46:12');
INSERT INTO `t_role` VALUES (2,'aix','系统监控员', '2017-12-12 09:46:12', '2017-12-12 09:46:12');
-- 用户角色关联表
DROP TABLE IF EXISTS `t_manager_role`;
CREATE TABLE `t_manager_role` (
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`manager_id` INT(11) NOT NULL COMMENT '管理用户ID',
`role_id` INT(11) NOT NULL COMMENT '角色ID',
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户角色关联表';
INSERT INTO `t_manager_role` VALUES (1, 1, 1, '2017-05-05 00:00:00','2017-05-05 00:00:00');
INSERT INTO `t_manager_role` VALUES (2, 2, 2, '2017-05-05 00:00:00','2017-05-05 00:00:00');
-- 权限表
DROP TABLE IF EXISTS `t_permission`;
CREATE TABLE `t_permission` (
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`permission` VARCHAR(16) DEFAULT '' COMMENT '权限名称',
`description` VARCHAR(255) DEFAULT '' COMMENT '权限说明',
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='权限表';
INSERT INTO `t_permission` VALUES (1,'permission:admin','超级管理权限', '2017-12-12 09:46:12', '2017-12-12 09:46:12');
INSERT INTO `t_permission` VALUES (2,'permission:aix','监控权限', '2017-12-12 09:46:12', '2017-12-12 09:46:12');
INSERT INTO `t_permission` VALUES (3,'permission:adduser','添加用户权限', '2017-12-12 09:46:12', '2017-12-12 09:46:12');
-- 角色权限关联表
DROP TABLE IF EXISTS `t_role_permission`;
CREATE TABLE `t_role_permission` (
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`role_id` INT(11) NOT NULL COMMENT '角色ID',
`permission_id` INT(11) NOT NULL COMMENT '权限ID',
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='角色权限关联表';
INSERT INTO `t_role_permission` VALUES (1, 1, 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');
INSERT INTO `t_role_permission` VALUES (2, 1, 3, '2017-12-12 09:46:12', '2017-12-12 09:46:12');
INSERT INTO `t_role_permission` VALUES (3, 2, 2, '2017-12-12 09:46:12', '2017-12-12 09:46:12');
-- 操作日志表
DROP TABLE IF EXISTS `t_operation_log`;
CREATE TABLE `t_operation_log` (
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`operator_id` INT(11) NOT NULL COMMENT '操作者ID',
`target_id` INT(11) NOT NULL COMMENT '操作对象ID',
`target_name` VARCHAR(32) DEFAULT '' COMMENT '操作对象名称',
`operate_type` VARCHAR(32) DEFAULT '' COMMENT '操作类型',
`tips` VARCHAR(255) DEFAULT '' COMMENT '备注',
`created_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB AUTO_INCREMENT=985 DEFAULT CHARSET=utf8 COMMENT='操作日志表';

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
package com.enzhico.jwt;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* 测试密码加密
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {
}

View File

@ -0,0 +1,74 @@
package com.enzhico.jwt;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPListParseEngine;
import org.apache.commons.net.ftp.FTPReply;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
/**
* FTPClientTest
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/24
*/
public class FTPClientTest {
@Test
public void connect() throws Exception {
FTPClient f = new FTPClient();
String server = "119.29.12.177";
f.setControlEncoding("UTF-8");
f.connect(server);
boolean login = f.login("ftpuser1", "123456");
System.out.println("login = " + login);
f.setDefaultPort(11024);
System.out.println("reply = " + f.getReplyString());
int replyCode = f.getReplyCode();
System.out.println("replyCode = " + replyCode);
if (!FTPReply.isPositiveCompletion(replyCode)) {
f.disconnect();
System.err.println("FTP server refused connection.");
}
f.enterLocalPassiveMode();
//f.enterLocalActiveMode();
FTPListParseEngine engine = f.initiateListParsing("");
while (engine.hasNext()) {
FTPFile[] files = engine.getNext(25); // "page size" you want
System.out.println("当前目录的文件数量 = " + files.length);
for (FTPFile ftpFile : files) {
System.out.println("文件名:" + ftpFile.getName());
}
//do whatever you want with these files, display them, etc.
//expensive FTPFile objects not created until needed.
}
f.disconnect();
}
@Test
public void upload() throws Exception {
FTPClient ftpClient = new FTPClient();
String server = "119.29.12.177";
ftpClient.connect(server);
ftpClient.login("ftpuser1", "123456");
InputStream sourceStream = null;
try {
sourceStream = new FileInputStream(new File(""));
//设置上传目录
ftpClient.changeWorkingDirectory("");
ftpClient.setBufferSize(1024);
ftpClient.setControlEncoding("UTF-8");
//设置文件类型二进制
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.storeFile("hero.txt", sourceStream);
} finally {
sourceStream.close();
ftpClient.disconnect();
}
}
}

View File

@ -0,0 +1,47 @@
package com.enzhico.jwt;
import com.enzhico.jwt.api.model.VersionParam;
import com.enzhico.jwt.shiro.ShiroKit;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.swagger2markup.markup.builder.MarkupLanguage;
import io.github.swagger2markup.GroupBy;
import io.github.swagger2markup.Language;
import io.github.swagger2markup.Swagger2MarkupConfig;
import io.github.swagger2markup.Swagger2MarkupConverter;
import io.github.swagger2markup.builder.Swagger2MarkupConfigBuilder;
import io.github.swagger2markup.markup.builder.MarkupLanguage;
import org.junit.Test;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* SimpleTest
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/4
*/
public class SimpleTest {
@Test
public void testMd5() {
//用户名+随机数
String username = "admin";
String salt = ShiroKit.getRandomSalt(16);
//原密码
String password = "12345678";
String encodedPassword = ShiroKit.md5(password, username + salt);
System.out.println("这个是保存进数据库的密码:" + encodedPassword);
System.out.println("这个是保存进数据库的盐:" + salt);
}
@Test
public void testJackson() throws JsonProcessingException {
VersionParam req = new VersionParam();
String reqBody = new ObjectMapper().writeValueAsString(req);
System.out.println(reqBody);
}
}

View File

@ -0,0 +1,112 @@
package com.enzhico.jwt;
import io.github.swagger2markup.GroupBy;
import io.github.swagger2markup.Language;
import io.github.swagger2markup.Swagger2MarkupConfig;
import io.github.swagger2markup.Swagger2MarkupConverter;
import io.github.swagger2markup.builder.Swagger2MarkupConfigBuilder;
import io.github.swagger2markup.markup.builder.MarkupLanguage;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import java.io.BufferedWriter;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Swagger2MarkupTest
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/26
*/
@AutoConfigureMockMvc
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class Swagger2MarkupTest {
@Autowired
private MockMvc mockMvc;
private static final Logger LOG = LoggerFactory.getLogger(Swagger2MarkupTest.class);
/**
* 自动生成adoc文件
* @throws Exception e
*
* 执行完成后生成PDF文件方法
*
* 首先在`build/swagger.adoc`的顶部加入
```
:toclevels: 3
:numbered:
```
注意有个空行分割目的是左边导航菜单是3级并且自动加序号
为了美化显示还要将`swagger.adoc`中全局替换一下
```
cols=".^2,.^3,.^9,.^4,.^2"
```
替换成
```
cols=".^2,.^3,.^6,.^4,.^5"
```
然后在/resources目录下面执行
```
asciidoctor-pdf -r asciidoctor-pdf-cjk-kai_gen_gothic -a pdf-style=KaiGenGothicCN swagger/swagger.adoc
```
会在`swagger.adoc`的同级目录生成`swagger.pdf`文件
*/
@Test
public void createSpringFoxSwaggerJson() throws Exception {
// String outputDir = System.getProperty("swaggerOutputDir"); // mvn test
MvcResult mvcResult = this.mockMvc.perform(get("/v2/api-docs")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn();
MockHttpServletResponse response = mvcResult.getResponse();
String swaggerJson = response.getContentAsString();
// Files.createDirectories(Paths.get(outputDir));
// try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(outputDir, "swagger.json"), StandardCharsets.UTF_8)){
// writer.write(swaggerJson);
// }
LOG.info("--------------------swaggerJson create --------------------");
convertAsciidoc(swaggerJson);
LOG.info("--------------------swagon.json to asciiDoc finished --------------------");
}
/**
* 将swagger.yaml或swagger.json转换成漂亮的 AsciiDoc
* 访问http://localhost:9095/v2/api-docs
* 将页面结果保存为src/main/resources/swagger.json
*/
private void convertAsciidoc(String swaggerStr) {
// Path localSwaggerFile = Paths.get(System.getProperty("swaggerOutputDir"), "swagger.json");
Path outputFile = Paths.get(System.getProperty("asciiDocOutputDir"));
Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
.withMarkupLanguage(MarkupLanguage.ASCIIDOC)
.withOutputLanguage(Language.ZH)
.withPathsGroupedBy(GroupBy.TAGS)
.withGeneratedExamples()
.withoutInlineSchema()
.build();
Swagger2MarkupConverter converter = Swagger2MarkupConverter.from(swaggerStr)
.withConfig(config)
.build();
converter.toFile(outputFile);
}
}

View File

@ -0,0 +1,24 @@
package com.enzhico.jwt.common.util;
import org.junit.Test;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
public class CommonUtilTest {
@Test
public void isNewer() {
assertThat(CommonUtil.isNewer("1.2.1", "1.2.0"), is(true));
assertThat(CommonUtil.isNewer("1.2", "1.2.0"), is(false));
assertThat(CommonUtil.isNewer("2.1.9", "1.2.0"), is(true));
assertThat(CommonUtil.isNewer("adfa.1.3", "1.2.0"), is(false));
}
@Test
public void testTimestamp() {
// 1516072088813
// 1441594722
System.out.println(System.currentTimeMillis());
}
}

View File

@ -0,0 +1,87 @@
package com.enzhico.jwt.socket.client;
import com.enzhico.jwt.common.util.JsonConverter;
import com.enzhico.jwt.socket.model.LoginRequest;
import io.socket.client.Ack;
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.stream.Collectors;
/**
* SocketClient
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/18
*/
public class SocketClient {
private static Socket socket;
private static final Logger logger = LoggerFactory.getLogger(SocketClient.class);
public static void main(String[] args) throws URISyntaxException {
IO.Options options = new IO.Options();
options.transports = new String[]{"websocket"};
options.reconnectionAttempts = 2;
options.reconnectionDelay = 1000; // 失败重连的时间间隔(ms)
options.timeout = 20000; // 连接超时时间(ms)
options.forceNew = true;
options.query = "username=test1&password=test1&appid=com.enzhico.apay2";
socket = IO.socket("http://localhost:9099/", options);
// socket = IO.socket("http://123.207.66.156:9099/", options);
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
// 客户端一旦连接成功开始发起登录请求
LoginRequest message = new LoginRequest(12, "这是客户端消息体");
socket.emit("login", JsonConverter.objectToJSONObject(message), (Ack) args1 -> {
logger.info("回执消息=" + Arrays.stream(args1).map(Object::toString).collect(Collectors.joining(",")));
});
}
}).on("login", new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.info("接受到服务器房间广播的登录消息:" + Arrays.toString(args));
}
}).on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.info("Socket.EVENT_CONNECT_ERROR");
socket.disconnect();
}
}).on(Socket.EVENT_CONNECT_TIMEOUT, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.info("Socket.EVENT_CONNECT_TIMEOUT");
socket.disconnect();
}
}).on(Socket.EVENT_PING, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.info("Socket.EVENT_PING");
}
}).on(Socket.EVENT_PONG, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.info("Socket.EVENT_PONG");
}
}).on(Socket.EVENT_MESSAGE, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.info("-----------接受到消息啦--------" + Arrays.toString(args));
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.info("客户端断开连接啦。。。");
// socket.disconnect();
}
});
socket.connect();
}
}

View File

@ -0,0 +1,85 @@
package com.enzhico.jwt.socket.client;
import com.enzhico.jwt.api.model.BaseResponse;
import com.enzhico.jwt.api.model.JoinBindResponse;
import com.enzhico.jwt.api.model.PosParam;
import com.enzhico.jwt.common.util.JsonConverter;
import io.socket.client.Ack;
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URISyntaxException;
/**
* 这个客户端和SpringBoot服务器连接测试
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/18
*/
public class SocketClient2 {
private static Socket socket;
private static final Logger logger = LoggerFactory.getLogger(SocketClient2.class);
public static void main(String[] args) throws URISyntaxException {
IO.Options options = new IO.Options();
options.transports = new String[]{"websocket"};
options.reconnectionAttempts = 2;
options.reconnectionDelay = 1000; // 失败重连的时间间隔(ms)
options.timeout = 6000; // 连接超时时间(ms)
options.forceNew = true;
options.query = "token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhcHBpZCI6ImNvbS5lbnpoaWNvLmFkbWlucGF5IiwiaW1laSI6Ijg2NjAzMzAzMDkwNjAwMCIsImV4cCI6MTUxNjc5OTM5MCwidXNlcm5hbWUiOiJhZG1pbiJ9.tmw6Ac46Wjad9hR-xT6RWHHwfviEqML5_2iK9zI1HeY";
socket = IO.socket("https://test.enzhico.net/", options);
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.info("我连接成功啦啦啦,开始进行入网查询....");
// 客户端一旦连接成功开始发起查询入网请求
String imei = "313123123123123";
socket.emit("askJoin", imei, (Ack) args1 -> {
JoinBindResponse r = JsonConverter.jsonObjectToObject(args1[0], JoinBindResponse.class);
logger.info("入网查询结果=" + r.getCode());
});
// 然后测试一下入网请求接口
PosParam posParam = new PosParam();
posParam.setImei("2222222222222222");
socket.emit("doJoin", JsonConverter.objectToJSONObject(posParam), (Ack) args1 -> {
BaseResponse r = JsonConverter.jsonObjectToObject(args1[0], JoinBindResponse.class);
logger.info("执行POS机入网结果=" + r.isSuccess() + ",msg=" + r.getMsg());
});
}
}).on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.info("Socket.EVENT_CONNECT_ERROR");
socket.disconnect();
}
}).on(Socket.EVENT_CONNECT_TIMEOUT, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.info("Socket.EVENT_CONNECT_TIMEOUT");
socket.disconnect();
}
}).on(Socket.EVENT_PING, new Emitter.Listener() {
@Override
public void call(Object... args) {
//logger.info(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + ": Socket.EVENT_PING");
}
}).on(Socket.EVENT_PONG, new Emitter.Listener() {
@Override
public void call(Object... args) {
//logger.info(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + ": Socket.EVENT_PONG");
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.info("客户端断开连接啦。。。");
socket.disconnect();
}
});
socket.connect();
}
}

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