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

View File

@ -0,0 +1,12 @@
package com.enzhico.pos;
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,37 @@
package com.enzhico.pos.async;
/**
* 异步方法异常
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/25
*/
public class AsyncException extends RuntimeException {
public AsyncException() {
super();
}
public AsyncException(String msg) {
super(msg);
}
public AsyncException(int code, String msg) {
super(msg);
this.code = code;
}
/**
* 错误代码
*/
private int code;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}

View File

@ -0,0 +1,30 @@
package com.enzhico.pos.async;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* AsyncExceptionHandler
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/25
*/
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(AsyncExceptionHandler.class);
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
log.error("Async method has uncaught exception, params:{}" + Arrays.toString(params));
if (ex instanceof AsyncException) {
AsyncException asyncException = (AsyncException) ex;
log.error("asyncException:" + asyncException.getMessage());
}
log.error("Exception :", ex);
}
}

View File

@ -0,0 +1,106 @@
package com.enzhico.pos.async;
import com.enzhico.pos.common.dao.entity.Pos;
import com.enzhico.pos.config.properties.MyProperties;
import com.enzhico.pos.dao.entity.ManagerInfo;
import com.enzhico.pos.http.HttpBaseResponse;
import com.enzhico.pos.http.LoginParam;
import com.enzhico.pos.http.UnbindParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.Future;
/**
* AsyncDemo
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/25
*/
@Component
public class AsyncTask {
private static final Logger logger = LoggerFactory.getLogger(AsyncTask.class);
@Resource
private MyProperties p;
@Resource
private RestTemplate restTemplate;
@Async
public void dealNoReturnTask() {
logger.info("返回值为void的异步调用开始" + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("返回值为void的异步调用结束" + Thread.currentThread().getName());
}
@Async
public Future<String> dealHaveReturnTask(int i) {
logger.info("asyncInvokeReturnFuture, parementer=" + i);
Future<String> future;
try {
Thread.sleep(1000 * i);
future = new AsyncResult<String>("success:" + i);
} catch (InterruptedException e) {
future = new AsyncResult<String>("error");
}
return future;
}
/**
* 异步推送消息
*/
@Async
public void pushUnbindMsg(ManagerInfo managerInfo, Pos pos, String location) {
logger.info("解绑成功后推送消息给对应的POS机");
LoginParam loginParam = new LoginParam();
loginParam.setUsername(managerInfo.getUsername());
loginParam.setPassword(managerInfo.getPassword());
HttpBaseResponse r = restTemplate.postForObject(
p.getPosapiUrlPrefix() + "/notifyLogin", loginParam, HttpBaseResponse.class);
if (r.isSuccess()) {
logger.info("推送消息登录认证成功");
String token = (String) r.getData();
UnbindParam unbindParam = new UnbindParam();
unbindParam.setImei(pos.getImei());
unbindParam.setLocation(location);
// 设置HTTP Header信息
URI uri;
try {
uri = new URI(p.getPosapiUrlPrefix() + "/notify/unbind");
} catch (URISyntaxException e) {
logger.error("URI构建失败", e);
throw new AsyncException("URI构建失败");
}
RequestEntity<UnbindParam> requestEntity = RequestEntity
.post(uri)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.header("Authorization", token)
.body(unbindParam);
ResponseEntity<HttpBaseResponse> responseEntity = restTemplate.exchange(requestEntity, HttpBaseResponse.class);
HttpBaseResponse r2 = responseEntity.getBody();
if (r2.isSuccess()) {
logger.info("推送消息解绑网点成功");
} else {
logger.error("推送消息解绑网点失败errmsg = " + r2.getMsg());
}
} else {
logger.error("推送消息登录认证失败");
}
}
}

View File

@ -0,0 +1,37 @@
package com.enzhico.pos.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,78 @@
package com.enzhico.pos.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,271 @@
package com.enzhico.pos.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,139 @@
package com.enzhico.pos.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,249 @@
package com.enzhico.pos.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,139 @@
package com.enzhico.pos.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,205 @@
package com.enzhico.pos.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,139 @@
package com.enzhico.pos.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,359 @@
package com.enzhico.pos.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,183 @@
package com.enzhico.pos.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,205 @@
package com.enzhico.pos.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,161 @@
package com.enzhico.pos.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,139 @@
package com.enzhico.pos.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,139 @@
package com.enzhico.pos.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,139 @@
package com.enzhico.pos.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.pos.common.dao.repository;
import com.enzhico.pos.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.pos.common.dao.repository;
import com.enzhico.pos.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.pos.common.dao.repository;
import com.enzhico.pos.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.pos.common.dao.repository;
import com.enzhico.pos.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.pos.common.dao.repository;
import com.enzhico.pos.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.pos.common.dao.repository;
import com.enzhico.pos.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.pos.common.dao.repository;
import com.enzhico.pos.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.pos.common.dao.repository;
import com.enzhico.pos.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.pos.common.dao.repository;
import com.enzhico.pos.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.pos.common.dao.repository;
import com.enzhico.pos.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.pos.common.dao.repository;
import com.enzhico.pos.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.pos.common.dao.repository;
import com.enzhico.pos.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.pos.common.dao.repository;
import com.enzhico.pos.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,146 @@
package com.enzhico.pos.common.util;
import android.content.res.AXmlResourceParser;
import android.util.TypedValue;
import org.xmlpull.v1.XmlPullParser;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class AnalysisApk {
/**
* 解压 zip 文件(apk可以当成一个zip文件),注意不能解压 rar 文件哦,只能解压 zip 文件 解压 rar 文件 会出现
* java.io.IOException: Negative seek offset 异常 create date:2009- 6- 9
* author:Administrator
*
* @param apkUrl zip 文件,注意要是正宗的 zip 文件哦,不能是把 rar 的直接改为 zip 这样会出现
* java.io.IOException: Negative seek offset 异常
* @param logoUrl 图标生成的地址
* @throws IOException
*/
public static String[] unZip(String apkUrl, String logoUrl) throws IOException {
// [0]:版本号;[1]包名
String[] st = new String[3];
byte b[] = new byte[1024];
int length;
ZipFile zipFile;
zipFile = new ZipFile(new File(apkUrl));
Enumeration<?> enumeration = zipFile.entries();
ZipEntry zipEntry = null;
while (enumeration.hasMoreElements()) {
zipEntry = (ZipEntry) enumeration.nextElement();
if (zipEntry.isDirectory()) {
} else {
if ("AndroidManifest.xml".equals(zipEntry.getName())) {
InputStream is = null;
AXmlResourceParser parser = null;
try {
parser = new AXmlResourceParser();
is = zipFile.getInputStream(zipEntry);
parser.open(is);
while (true) {
int type = parser.next();
if (type == XmlPullParser.END_DOCUMENT) {
break;
}
switch (type) {
case XmlPullParser.START_TAG: {
for (int i = 0; i != parser.getAttributeCount(); ++i) {
if ("versionName".equals(parser.getAttributeName(i))) {
st[0] = getAttributeValue(parser, i);
} else if ("versionCode".equals(parser.getAttributeName(i))) {
st[1] = getAttributeValue(parser, i);
} else if ("package".equals(parser.getAttributeName(i))) {
st[2] = getAttributeValue(parser, i);
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) is.close();
if (parser != null) parser.close();
}
}
// if ("res/drawable-ldpi/icon.png".equals(zipEntry.getName())) {
// OutputStream outputStream = new FileOutputStream(logoUrl);
// InputStream inputStream = zipFile.getInputStream(zipEntry);
// while ((length = inputStream.read(b)) > 0)
// outputStream.write(b, 0, length);
// }
}
}
zipFile.close();
return st;
}
private static String getAttributeValue(AXmlResourceParser parser, int index) {
int type = parser.getAttributeValueType(index);
int data = parser.getAttributeValueData(index);
if (type == TypedValue.TYPE_STRING) {
return parser.getAttributeValue(index);
}
if (type == TypedValue.TYPE_ATTRIBUTE) {
return String.format("?%s%08X", getPackage(data), data);
}
if (type == TypedValue.TYPE_REFERENCE) {
return String.format("@%s%08X", getPackage(data), data);
}
if (type == TypedValue.TYPE_FLOAT) {
return String.valueOf(Float.intBitsToFloat(data));
}
if (type == TypedValue.TYPE_INT_HEX) {
return String.format("0x%08X", data);
}
if (type == TypedValue.TYPE_INT_BOOLEAN) {
return data != 0 ? "true" : "false";
}
if (type == TypedValue.TYPE_DIMENSION) {
return Float.toString(complexToFloat(data)) + DIMENSION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK];
}
if (type == TypedValue.TYPE_FRACTION) {
return Float.toString(complexToFloat(data)) + FRACTION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK];
}
if (type >= TypedValue.TYPE_FIRST_COLOR_INT && type <= TypedValue.TYPE_LAST_COLOR_INT) {
return String.format("#%08X", data);
}
if (type >= TypedValue.TYPE_FIRST_INT && type <= TypedValue.TYPE_LAST_INT) {
return String.valueOf(data);
}
return String.format("<0x%X, type 0x%02X>", data, type);
}
private static String getPackage(int id) {
if (id >>> 24 == 1) {
return "android:";
}
return "";
}
// ///////////////////////////////// ILLEGAL STUFF, DONT LOOK :)
public static float complexToFloat(int complex) {
return (float) (complex & 0xFFFFFF00) * RADIX_MULTS[(complex >> 4) & 3];
}
private static final float RADIX_MULTS[] = {0.00390625F, 3.051758E-005F, 1.192093E-007F, 4.656613E-010F};
private static final String DIMENSION_UNITS[] = {"px", "dip", "sp", "pt", "in", "mm", "", ""};
private static final String FRACTION_UNITS[] = {"%", "%p", "", "", "", "", "", ""};
public static void main(String[] args) throws IOException {
String path = "C:/Users/alexshi/Downloads/tempDownload/app-release.apk";
String[] messag = AnalysisApk.unZip(path, "C:/Users/alexshi/Downloads/uploadPrepared");
System.out.println(messag[0] + "-------->" + messag[1]);
}
}

View File

@ -0,0 +1,40 @@
package com.enzhico.pos.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,294 @@
/**
* 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.pos.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,47 @@
package com.enzhico.pos.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,41 @@
package com.enzhico.pos.config;
import com.enzhico.pos.async.AsyncExceptionHandler;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
/**
* AsyncConfig
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/25
*/
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(100);
executor.setQueueCapacity(100);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60 * 10);
executor.setThreadNamePrefix("AsyncThread-");
executor.initialize(); //如果不初始化,导致找到不到执行器
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncExceptionHandler();
}
}

View File

@ -0,0 +1,47 @@
package com.enzhico.pos.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import com.enzhico.pos.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.pos.common.dao.repository",
"com.enzhico.pos.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,59 @@
package com.enzhico.pos.config;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* RestTemplate客户端连接池配置
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/24
*/
@Configuration
public class RestClientConfig {
@Bean
public ClientHttpRequestFactory httpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return new RestTemplate(httpRequestFactory());
}
@Bean
public HttpClient httpClient() {
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
connectionManager.setMaxTotal(5);
connectionManager.setDefaultMaxPerRoute(5);
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(8000)
.setConnectTimeout(8000)
.setConnectionRequestTimeout(8000)
.build();
return HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
.build();
}
}

View File

@ -0,0 +1,31 @@
package com.enzhico.pos.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* ScheduleConfig
*
* @author XiongNeng
* @version 1.0
* @since 2017/9/13
*/
@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
@Bean(destroyMethod="shutdown")
public ExecutorService taskExecutor() {
return Executors.newScheduledThreadPool(5);
}
}

View File

@ -0,0 +1,277 @@
package com.enzhico.pos.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.servlet.KaptchaServlet;
import com.enzhico.pos.shiro.KaptchaFilter;
import com.enzhico.pos.shiro.MyExceptionResolver;
import com.enzhico.pos.shiro.MyShiroRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
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 {
//配置kaptcha图片验证码框架提供的Servlet,,这是个坑,很多人忘记注册(注意)
@Bean
public ServletRegistrationBean kaptchaServlet() {
ServletRegistrationBean servlet = new ServletRegistrationBean(new KaptchaServlet(), "/kaptcha.jpg");
servlet.addInitParameter(Constants.KAPTCHA_SESSION_CONFIG_KEY, Constants.KAPTCHA_SESSION_KEY);//session key
servlet.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, "50");//字体大小
servlet.addInitParameter(Constants.KAPTCHA_BORDER, "no");
servlet.addInitParameter(Constants.KAPTCHA_BORDER_COLOR, "105,179,90");
servlet.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, "45");
servlet.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
servlet.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES, "宋体,楷体,微软雅黑");
servlet.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
servlet.addInitParameter(Constants.KAPTCHA_IMAGE_WIDTH, "125");
servlet.addInitParameter(Constants.KAPTCHA_IMAGE_HEIGHT, "60");
//可以设置很多属性,具体看com.google.code.kaptcha.Constants
// kaptcha.border 是否有边框 默认为true 我们可以自己设置yesno
// kaptcha.border.color 边框颜色 默认为Color.BLACK
// kaptcha.border.thickness 边框粗细度 默认为1
// kaptcha.producer.impl 验证码生成器 默认为DefaultKaptcha
// kaptcha.textproducer.impl 验证码文本生成器 默认为DefaultTextCreator
// kaptcha.textproducer.char.string 验证码文本字符内容范围 默认为abcde2345678gfynmnpwx
// kaptcha.textproducer.char.length 验证码文本字符长度 默认为5
// kaptcha.textproducer.font.names 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
// kaptcha.textproducer.font.size 验证码文本字符大小 默认为40
// kaptcha.textproducer.font.color 验证码文本字符颜色 默认为Color.BLACK
// kaptcha.textproducer.char.space 验证码文本字符间距 默认为2
// kaptcha.noise.impl 验证码噪点生成对象 默认为DefaultNoise
// kaptcha.noise.color 验证码噪点颜色 默认为Color.BLACK
// kaptcha.obscurificator.impl 验证码样式引擎 默认为WaterRipple
// kaptcha.word.impl 验证码文本字符渲染 默认为DefaultWordRenderer
// kaptcha.background.impl 验证码背景生成器 默认为DefaultBackground
// kaptcha.background.clear.from 验证码背景颜色渐进 默认为Color.LIGHT_GRAY
// kaptcha.background.clear.to 验证码背景颜色渐进 默认为Color.WHITE
// kaptcha.image.width 验证码图片宽度 默认为200
// kaptcha.image.height 验证码图片高度 默认为50
return servlet;
}
//注入异常处理类
@Bean
public MyExceptionResolver myExceptionResolver() {
return new MyExceptionResolver();
}
/**
* 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();
KaptchaFilter kaptchaFilter = new KaptchaFilter();
filtersMap.put("kaptchaFilter", kaptchaFilter);
//实现自己规则roles,这是为了实现or的效果
//RoleFilter roleFilter = new RoleFilter();
//filtersMap.put("roles", roleFilter);
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>();
// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/logout", "logout");
//配置记住我或认证通过可以访问的地址
filterChainDefinitionMap.put("/index", "user");
filterChainDefinitionMap.put("/", "user");
filterChainDefinitionMap.put("/login", "kaptchaFilter");
// <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
//这段是配合 actuator框架使用的配置相应的角色才能访问
// filterChainDefinitionMap.put("/health", "roles[aix]");//服务器健康状况页面
// filterChainDefinitionMap.put("/info", "roles[aix]");//服务器信息页面
// filterChainDefinitionMap.put("/env", "roles[aix]");//应用程序的环境变量
// filterChainDefinitionMap.put("/metrics", "roles[aix]");
// filterChainDefinitionMap.put("/configprops", "roles[aix]");
//开放的静态资源
filterChainDefinitionMap.put("/favicon.ico", "anon");//网站图标
filterChainDefinitionMap.put("/static/**", "anon");//配置static文件下资源能被访问的这是个例子
filterChainDefinitionMap.put("/kaptcha.jpg", "anon");//图片验证码(kaptcha框架)
filterChainDefinitionMap.put("/api/v1/**", "anon");//API接口
// 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("/**", "authc");
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/index");
// 未授权界面,不生效(详情原因看MyExceptionResolver)
shiroFilterFactoryBean.setUnauthorizedUrl("/errorView/403_error.html");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(myShiroRealm());
//注入缓存管理器
securityManager.setCacheManager(ehCacheManager());//这个如果执行多次,也是同样的一个对象;
//注入记住我管理器;
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
/**
* 身份认证realm; (这个需要自己写,账号密码校验;权限等)
*/
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}
/**
* 凭证匹配器 由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
* 所以我们需要修改下doGetAuthenticationInfo中的代码; @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(2);// 散列的次数比如散列两次相当于md5(md5(""));
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);//表示是否存储散列后的密码为16进制需要和生成密码时的一样默认是base64
return hashedCredentialsMatcher;
}
/**
* 开启shiro aop注解支持. 使用代理方式; 所以需要开启代码支持;
*
* @param securityManager
* @return
*/
@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;
}
/**
* cookie对象;
*
* @return
*/
@Bean
public SimpleCookie rememberMeCookie() {
//System.out.println("ShiroConfiguration.rememberMeCookie()");
//这个参数是cookie的名称对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//<!-- 记住我cookie生效时间30天 ,单位秒;-->
simpleCookie.setMaxAge(259200);
return simpleCookie;
}
/**
* cookie管理对象;
*
* @return
*/
@Bean
public CookieRememberMeManager rememberMeManager() {
//System.out.println("ShiroConfiguration.rememberMeManager()");
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
return cookieRememberMeManager;
}
@Bean(name = "sessionManager")
public DefaultWebSessionManager defaultWebSessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(18000000);
// url中是否显示session Id
sessionManager.setSessionIdUrlRewritingEnabled(false);
// 删除失效的session
sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionValidationInterval(18000000);
sessionManager.setSessionValidationScheduler(getExecutorServiceSessionValidationScheduler());
//设置SessionIdCookie 导致认证不成功不从新设置新的cookie,从sessionManager获取sessionIdCookie
//sessionManager.setSessionIdCookie(simpleIdCookie());
sessionManager.getSessionIdCookie().setName("session-z-id");
sessionManager.getSessionIdCookie().setPath("/");
sessionManager.getSessionIdCookie().setMaxAge(60 * 60 * 24 * 7);
return sessionManager;
}
@Bean(name = "sessionValidationScheduler")
public ExecutorServiceSessionValidationScheduler getExecutorServiceSessionValidationScheduler() {
ExecutorServiceSessionValidationScheduler scheduler = new ExecutorServiceSessionValidationScheduler();
scheduler.setInterval(900000);
return scheduler;
}
@Bean(name = "shiroDialect")
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
}

View File

@ -0,0 +1,102 @@
package com.enzhico.pos.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.pos.shiro.*.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.pos.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;
private String username;
private String password;
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,148 @@
package com.enzhico.pos.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 {
/**
* excel模板文件路径
*/
private String excelPath = "";
/**
* 文件保存路径
*/
private String filesPath = "";
/**
* 图片保存路径
*/
private String picsPath = "";
/**
* 图片访问URL前缀
*/
private String picsUrlPrefix = "";
/**
* 文件访问URL前缀
*/
private String filesUrlPrefix = "";
/**
* POS API接口前缀
*/
private String posapiUrlPrefix = "";
/**
* 是否验证码
*/
private Boolean kaptchaOpen = false;
/**
* 是否开启Swaggr
*/
private Boolean swaggerOpen = false;
/**
* session 失效时间默认为30分钟 单位:秒)
*/
private Integer sessionInvalidateTime = 30 * 60;
/**
* session 验证失效时间默认为15分钟 单位:秒)
*/
private Integer sessionValidationInterval = 15 * 60;
/**
* 机具心跳报告超时时间 单位:分钟
*/
private Integer heartbeatTimeout;
public String getExcelPath() {
return excelPath;
}
public void setExcelPath(String excelPath) {
this.excelPath = excelPath;
}
public String getPicsUrlPrefix() {
return picsUrlPrefix;
}
public void setPicsUrlPrefix(String picsUrlPrefix) {
this.picsUrlPrefix = picsUrlPrefix;
}
public Boolean getKaptchaOpen() {
return kaptchaOpen;
}
public void setKaptchaOpen(Boolean kaptchaOpen) {
this.kaptchaOpen = kaptchaOpen;
}
public Boolean getSwaggerOpen() {
return swaggerOpen;
}
public void setSwaggerOpen(Boolean swaggerOpen) {
this.swaggerOpen = swaggerOpen;
}
public Integer getSessionInvalidateTime() {
return sessionInvalidateTime;
}
public void setSessionInvalidateTime(Integer sessionInvalidateTime) {
this.sessionInvalidateTime = sessionInvalidateTime;
}
public Integer getSessionValidationInterval() {
return sessionValidationInterval;
}
public void setSessionValidationInterval(Integer sessionValidationInterval) {
this.sessionValidationInterval = sessionValidationInterval;
}
public String getFilesUrlPrefix() {
return filesUrlPrefix;
}
public void setFilesUrlPrefix(String filesUrlPrefix) {
this.filesUrlPrefix = filesUrlPrefix;
}
public String getFilesPath() {
return filesPath;
}
public void setFilesPath(String filesPath) {
this.filesPath = filesPath;
}
public Integer getHeartbeatTimeout() {
return heartbeatTimeout;
}
public void setHeartbeatTimeout(Integer heartbeatTimeout) {
this.heartbeatTimeout = heartbeatTimeout;
}
public String getPicsPath() {
return picsPath;
}
public void setPicsPath(String picsPath) {
this.picsPath = picsPath;
}
public String getPosapiUrlPrefix() {
return posapiUrlPrefix;
}
public void setPosapiUrlPrefix(String posapiUrlPrefix) {
this.posapiUrlPrefix = posapiUrlPrefix;
}
}

View File

@ -0,0 +1,267 @@
package com.enzhico.pos.controller;
import com.baomidou.mybatisplus.plugins.Page;
import com.enzhico.pos.common.dao.entity.Pos;
import com.enzhico.pos.common.util.AnalysisApk;
import com.enzhico.pos.common.util.DateUtil;
import com.enzhico.pos.config.properties.MyProperties;
import com.enzhico.pos.dao.entity.AppInfo;
import com.enzhico.pos.dao.entity.ManagerInfo;
import com.enzhico.pos.dao.entity.PublishParam;
import com.enzhico.pos.dao.entity.SearchApp;
import com.enzhico.pos.model.BaseResponse;
import com.enzhico.pos.service.AppService;
import com.enzhico.pos.shiro.ShiroKit;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.List;
/**
* Description: APP管理
*/
@Controller
@RequestMapping("/app")
public class AppController {
@Resource
private AppService appService;
@Resource
private MyProperties myProperties;
private static final Logger _logger = LoggerFactory.getLogger(AppController.class);
/**
* App管理首页
*
* @param request
* @param model
* @return
*/
@RequestMapping(value = "/index")
@RequiresUser
public String index(HttpServletRequest request, Model model) throws JsonProcessingException {
ManagerInfo managerInfo = ShiroKit.getUser();
// 应用名称和版本号对应关系
String json = new ObjectMapper().writeValueAsString(appService.selectAppVersionList(managerInfo.getPidsList()));
model.addAttribute("appVersionMap", json);
// 应用名称列表
model.addAttribute("appNames", appService.selectAllAppNames(managerInfo.getPidsList()));
// 版本号列表
model.addAttribute("versions", appService.selectAllVersions(managerInfo.getPidsList()));
// 项目名称列表
model.addAttribute("projects", appService.selectAllProjects(managerInfo.getPidsList()));
return "modules/app/appManagement";
}
/**
* 分页查询列表
*
* @return
*/
@RequestMapping(value = "/list")
@ResponseBody
@RequiresUser()
public BaseResponse list(@ModelAttribute SearchApp searchApp) {
// 日期范围分解
if (StringUtils.isNotEmpty(searchApp.getPublishtimeRange())) {
String[] ds = searchApp.getPublishtimeRange().split(" - ");
searchApp.setPublishTimeStart(DateUtil.getDateStartTime(DateUtil.parseDate(ds[0])));
searchApp.setPublishTimeEnd(DateUtil.getDateEndTime(DateUtil.parseDate(ds[1])));
}
// 设置项目ID
ManagerInfo managerInfo = ShiroKit.getUser();
searchApp.setPidList(managerInfo.getPidsList());
Page page = new Page(searchApp.getPageNumber(), searchApp.getPageSize());
List<AppInfo> list = appService.searchList(page, searchApp);
return new BaseResponse(true, "查询列表", page.getTotal(), list);
}
/**
* 灰度发布列表
*
* @return
*/
@RequestMapping(value = "/graylist")
@ResponseBody
@RequiresUser
public BaseResponse graylist(@RequestParam("id") Integer appId) {
List<Pos> list = appService.grayList(appId);
return new BaseResponse(true, "灰度发布列表", 0, list);
}
/**
* 全网发布
*
* @return
*/
@RequestMapping(value = "/publishall/{appId}", method = RequestMethod.POST)
@ResponseBody
@RequiresUser
public BaseResponse publishAll(@PathVariable("appId") Integer appId) {
appService.publishAll(appId);
return new BaseResponse(true, "全网发布成功", 0, null);
}
/**
* 发布新版本页面
*
* @param request
* @param model
* @return
*/
@RequestMapping(value = "/publish")
@RequiresUser
public String publish(HttpServletRequest request, Model model) {
// 项目名称列表
ManagerInfo managerInfo = ShiroKit.getUser();
// 应用名称列表
model.addAttribute("appNames", appService.selectAllAppNames(managerInfo.getPidsList()));
return "modules/app/addVersion";
}
/**
* 发布新版本
*
* @return
*/
@RequestMapping(value = "/publish", method = RequestMethod.POST)
@ResponseBody
@RequiresUser
public BaseResponse doPublish(@ModelAttribute PublishParam param) throws IOException {
// MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
// multipartRequest.getParameter("name");
_logger.info("app name=" + param.getName());
MultipartFile file = param.getFile();
String tempFile = param.getName() + "_" + System.currentTimeMillis() + ".apk";
if (!file.isEmpty()) {
File destFile = new File(myProperties.getFilesPath(), tempFile);
Path destFilePath = Paths.get(destFile.getAbsolutePath());
saveFile(file, destFile);
// 解析APK文件提取版本号和Application ID
String[] packageInfo;
try {
packageInfo = AnalysisApk.unZip(
new File(myProperties.getFilesPath(), tempFile).getAbsolutePath(), myProperties.getFilesPath());
} catch (IOException e) {
return new BaseResponse(false, "文件类型错误,请上传应用文件。", 0, null);
}
String appVersion = packageInfo[0];
if (appVersion == null) {
return new BaseResponse(false, "文件类型错误,请上传应用文件。", 0, null);
}
// String appVersionCode = packageInfo[1];
String applicationId = packageInfo[2];
// 先获取登录用户
ManagerInfo manager = ShiroKit.getUser();
// 做用户发布权限的检查
if (!appService.checkUserPublishPermission(manager.getId(), applicationId)) {
return new BaseResponse(false, "上传失败,你没有权限发布此应用", 0, null);
}
// 接下来做APK文件和版本号的合法性检查
boolean checkVersion;
try {
checkVersion = appService.checkAppVersion(applicationId, appVersion);
} catch (NullPointerException e) {
return new BaseResponse(false, "上传失败请先配置好Application Id = " + applicationId + "的项目", 0, null);
}
if (!checkVersion) {
Files.delete(destFilePath);
return new BaseResponse(false, "版本号较低,请重新上传", 0, null);
}
// 重命名文件
Files.move(destFilePath, destFilePath.resolveSibling(param.getName() + "_" + appVersion + ".apk"), StandardCopyOption.REPLACE_EXISTING);
// 更新参数
param.setVersion(appVersion);
param.setApplicationId(applicationId);
// 然后保存这条版本记录
appService.addVersion(param, manager);
return new BaseResponse(true, "上传成功", 0, null);
}
return new BaseResponse(false, "请上传应用文件", 0, null);
}
/**
* 灰度发布页面
*
* @return
*/
@RequestMapping(value = "/gray")
@RequiresUser
public String gray(HttpServletRequest request, Model model) {
// 项目名称列表
ManagerInfo managerInfo = ShiroKit.getUser();
model.addAttribute("locations", appService.selectAllLocations(managerInfo.getPidsList()));
return "modules/app/grayPublish";
}
/**
* 按网点查询POS列表
*
* @return
*/
@RequestMapping(value = "/listlo")
@ResponseBody
@RequiresUser
public BaseResponse listlo(@RequestParam("locations") String locations) {
if ("0".equals(locations)) {
return new BaseResponse(true, "网点查询POS列表", 0, null);
}
List<String> locationList = null;
if (StringUtils.isNotEmpty(locations)) {
locationList = Arrays.asList(locations.split(","));
}
List<Pos> posList = appService.selectPosListByLocations(locationList);
return new BaseResponse(true, "网点查询POS列表", posList != null ? posList.size() : 0, posList);
}
/**
* 按imei查询POS列表
*
* @return POS列表
*/
@RequestMapping(value = "/imei")
@ResponseBody
@RequiresUser
public BaseResponse imei(@RequestParam("imei") String imei) {
Pos pos = appService.selectByImei(imei);
return new BaseResponse(pos != null, "按imei查询POS列表", 0, pos);
}
/**
* 保存文件
* @param file 上传文件
* @param destFile 目标文件
*/
private void saveFile(MultipartFile file, File destFile) {
try {
FileUtils.copyInputStreamToFile(file.getInputStream(), destFile);
} catch (IOException ie) {
_logger.error("保存文件出错", ie);
}
}
}

View File

@ -0,0 +1,117 @@
package com.enzhico.pos.controller;
import com.baomidou.mybatisplus.plugins.Page;
import com.enzhico.pos.common.dao.entity.PosHistory;
import com.enzhico.pos.dao.entity.ManagerInfo;
import com.enzhico.pos.dao.entity.PosInfo;
import com.enzhico.pos.dao.entity.SearchPos;
import com.enzhico.pos.model.BaseResponse;
import com.enzhico.pos.service.DeviceService;
import com.enzhico.pos.shiro.ShiroKit;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* Description: 机具入网管理
*/
@Controller
@RequestMapping("/device")
public class DeviceController {
@Resource
private DeviceService deviceService;
/**
* 机具入网管理首页
*
* @param request
* @param model
* @return
*/
@RequestMapping(value = "/index")
@RequiresUser()
public String index(HttpServletRequest request, Model model) {
// 查询所有项目列表
ManagerInfo managerInfo = ShiroKit.getUser();
model.addAttribute("projects", deviceService.allProjects(managerInfo.getPidsList()));
return "modules/device/deviceManagement";
}
/**
* 机具详情
*
* @return
*/
@RequestMapping(value = "/detail")
@RequiresUser()
public String detail(Model model, @RequestParam("id") Integer id) {
PosInfo posInfo = deviceService.searchDetail(id);
model.addAttribute("pos", posInfo);
return "modules/device/deviceDetail";
}
/**
* 查询列表
*
* @return
*/
@RequestMapping(value = "/list")
@ResponseBody
@RequiresUser()
public BaseResponse list(@ModelAttribute SearchPos searchPos) {
Page page = new Page(searchPos.getPageNumber(), searchPos.getPageSize());
ManagerInfo managerInfo = ShiroKit.getUser();
searchPos.setPidList(managerInfo.getPidsList());
List<PosInfo> list = deviceService.searchList(page, searchPos);
return new BaseResponse(true, "设备列表", page.getTotal(), list);
}
/**
* 修改机具状态
*
* @return
*/
@RequestMapping(value = "/state/{id}/{state}", method = RequestMethod.POST)
@ResponseBody
@RequiresUser()
public BaseResponse state(@PathVariable("id") Integer id,
@PathVariable("state") Integer state) {
deviceService.updateState(id, state);
return new BaseResponse(true, "修改状态成功", 0, null);
}
/**
* 解除网点绑定
*
* @return
*/
@RequestMapping(value = "/unbind/{id}", method = RequestMethod.POST)
@ResponseBody
@RequiresUser()
public BaseResponse unbind(@PathVariable("id") Integer id) {
ManagerInfo managerInfo = ShiroKit.getUser();
deviceService.unbind(id, managerInfo);
return new BaseResponse(true, "解除网点绑定成功", 0, null);
}
/**
* 查询绑定历史
*
* @return
*/
@RequestMapping(value = "/history/{posId}", method = RequestMethod.GET)
@ResponseBody
@RequiresUser()
public BaseResponse bindHistory(@PathVariable("posId") Integer id) {
List<PosHistory> historyList = deviceService.selectHisotryList(id);
return new BaseResponse(true, "查询绑定历史", 0, historyList);
}
}

View File

@ -0,0 +1,157 @@
package com.enzhico.pos.controller;
import com.enzhico.pos.config.properties.MyProperties;
import com.enzhico.pos.dao.entity.ManagerInfo;
import com.enzhico.pos.exception.ForbiddenUserException;
import com.enzhico.pos.service.ManagerInfoService;
import com.enzhico.pos.service.ProjectService;
import com.enzhico.pos.shiro.IncorrectCaptchaException;
import com.enzhico.pos.shiro.ShiroKit;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
/**
* Description: 登录验证
*/
// 只用同时具有permission:view和permission:aix权限才能访问
//@RequiresPermissions(value={"permission:view","permission:aix"}, logical= Logical.AND)
//@RequiresPermissions(value={"permission:view","permission:aix"}, logical= Logical.OR)一个就行
@Controller
public class LoginController {
@Resource
private ManagerInfoService managerInfoService;
@Resource
private ProjectService projectService;
@Resource
private MyProperties myProperties;
private static final Logger _logger = LoggerFactory.getLogger(LoginController.class);
//登录页(shiro配置需要两个/login 接口,一个是get用来获取登陆页面,一个用post用于登录)
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login() {
if (ShiroKit.isAuthenticated()) {
return "redirect:/";
}
return "login";
}
// 登录提交地址和applicationontext-shiro.xml配置的loginurl一致。 (配置文件方式的说法)
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(HttpServletRequest request, Map<String, Object> map) {
_logger.info("登录方法start.........");
// 登录失败从request中获取shiro处理的异常信息。shiroLoginFailure:就是shiro异常类的全类名.
Object exception = request.getAttribute("shiroLoginFailure");
String msg;
if (exception != null) {
if (UnknownAccountException.class.isInstance(exception)) {
msg = "用户名不正确,请重新输入";
} else if (IncorrectCredentialsException.class.isInstance(exception)) {
msg = "密码错误,请重新输入";
} else if (IncorrectCaptchaException.class.isInstance(exception)) {
msg = "验证码错误";
} else if (ForbiddenUserException.class.isInstance(exception)) {
msg = "该用户已被禁用,如有疑问请联系系统管理员。";
} else {
msg = "发生未知错误,请联系管理员。";
}
map.put("username", request.getParameter("username"));
map.put("password", request.getParameter("password"));
map.put("msg", msg);
return "login";
}
//如果已经登录,直接跳转主页面
return "index";
}
/**
* 主页
* @param session
* @param model
* @return
*/
@RequestMapping({"/", "/index"})
public String index(HttpSession session, Model model) {
// _logger.info("访问首页start...");
// 做一些其他事情比如把项目的数量放到session中
if (ShiroKit.hasRole("admin") && session.getAttribute("projectNum") == null) {
int pnum = projectService.selectProjectNum();
session.setAttribute("projectNum", pnum);
}
if (session.getAttribute("picsUrlPrefix") == null) {
// 图片访问URL前缀
session.setAttribute("picsUrlPrefix", myProperties.getPicsUrlPrefix());
}
return "index";
}
/**
* 欢迎页面
* @param request
* @param model
* @return
*/
@RequestMapping("/welcome")
public String welcome(HttpServletRequest request, Model model) {
return "modules/common/welcome";
}
/**
* 修改密码
*
* @param request
* @param model
* @return
*/
@RequestMapping("/password")
@RequiresUser
public String password(HttpServletRequest request, Model model) {
return "modules/common/modifyPassword";
}
/**
* 修改密码
*
* @return
*/
@RequestMapping(value = "/password", method = RequestMethod.POST)
@RequiresUser
@ResponseBody
public Map<String, Object> changePassword(@RequestParam Map<String, String> param) {
_logger.info("修改密码 post start....");
Map<String, Object> result = new HashMap<>();
String oldPassword = param.get("p1");
String newPassword = param.get("p2");
ManagerInfo managerInfo = ShiroKit.getUser();
if (!ShiroKit.md5(oldPassword, managerInfo.getCredentialsSalt()).equals(managerInfo.getPassword())) {
result.put("success", false);
result.put("msg", "原密码不正确");
return result;
}
String newPasswordEncpt = ShiroKit.md5(newPassword, managerInfo.getCredentialsSalt());
managerInfoService.updatePassword(managerInfo.getUsername(), newPasswordEncpt);
managerInfo.setPassword(newPasswordEncpt);
result.put("success", true);
result.put("msg", "修改密码成功!");
return result;
}
}

View File

@ -0,0 +1,115 @@
package com.enzhico.pos.controller;
import com.baomidou.mybatisplus.plugins.Page;
import com.enzhico.pos.model.BaseResponse;
import com.enzhico.pos.common.dao.entity.Project;
import com.enzhico.pos.dao.entity.*;
import com.enzhico.pos.service.MonitorService;
import com.enzhico.pos.shiro.ShiroKit;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Description: 监控管理
*/
@Controller
@RequestMapping("/monitor")
public class MonitorController {
@Resource
private MonitorService monitorService;
/**
* 监控管理首页
*
* @param request
* @param model
* @return
*/
@RequestMapping(value = "/index")
@RequiresUser()
public String index(HttpServletRequest request, Model model) {
// 获取所有的项目
ManagerInfo managerInfo = ShiroKit.getUser();
List<Project> projects = monitorService.selectAllProjects(managerInfo.getPidsList());
model.addAttribute("projects", projects);
// 入网机具总数
model.addAttribute("posCount", monitorService.posCount(0, managerInfo.getPidsList()));
// 网点数量
model.addAttribute("locationCount", monitorService.locationCount(0, managerInfo.getPidsList()));
return "modules/monitor/deviceStatus";
}
/**
* 切换项目重新加载
*
* @return
*/
@RequestMapping(value = "/reload")
@ResponseBody
@RequiresUser()
public BaseResponse reload(@RequestParam("projectId") Integer projectId) {
Map<String, Integer> map = new HashMap<>();
ManagerInfo managerInfo = ShiroKit.getUser();
map.put("posCount", monitorService.posCount(projectId, managerInfo.getPidsList()));
map.put("locationCount", monitorService.locationCount(projectId, managerInfo.getPidsList()));
return new BaseResponse(true,"重新加载", 0, map);
}
/**
* 网点分组机具分页查询
*
* @return
*/
@RequestMapping(value = "/list")
@ResponseBody
@RequiresUser()
public BaseResponse list(@ModelAttribute SearchPos searchPos) {
Page page = new Page(searchPos.getPageNumber(), searchPos.getPageSize());
ManagerInfo managerInfo = ShiroKit.getUser();
searchPos.setPidList(managerInfo.getPidsList());
List<PosGroupInfo> list = monitorService.searchListGroupByLocation(page, searchPos);
return new BaseResponse(true, "网点分组机具分页查询", page.getTotal(), list);
}
/**
* 网点机具详情页面
*
* @return
*/
@RequestMapping(value = "/detail")
@RequiresUser()
public String detail(Model model, @RequestParam("location") String location) {
model.addAttribute("location", location);
return "modules/monitor/deviceStatusDetail";
}
/**
* 特定网点机具列表分页
*
* @return
*/
@RequestMapping(value = "/detailList")
@ResponseBody
@RequiresUser()
public BaseResponse detailList(@ModelAttribute SearchMonitor searchMonitor) {
Page page = new Page(searchMonitor.getPageNumber(), searchMonitor.getPageSize());
ManagerInfo managerInfo = ShiroKit.getUser();
searchMonitor.setPidList(managerInfo.getPidsList());
List<MonitorInfo> list = monitorService.searchLocationMonitorList(page, searchMonitor);
return new BaseResponse(true, "特定网点机具列表分页", page.getTotal(), list);
}
}

View File

@ -0,0 +1,147 @@
package com.enzhico.pos.controller;
import com.enzhico.pos.common.dao.entity.Project;
import com.enzhico.pos.config.properties.MyProperties;
import com.enzhico.pos.dao.entity.FileInfo;
import com.enzhico.pos.model.BaseResponse;
import com.enzhico.pos.service.ProjectService;
import org.apache.commons.io.FileUtils;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.UUID;
/**
* Description: 项目管理
*/
@Controller
@RequestMapping("/project")
public class ProjectController {
private static final Logger _logger = LoggerFactory.getLogger(ProjectController.class);
@Resource
private ProjectService projectService;
@Resource
private MyProperties myProperties;
/**
* 项目管理首页
*
* @param request req
* @param model model
* @return 项目管理首页页面
*/
@RequestMapping(value = "/index")
@RequiresRoles("admin")
public String index(HttpServletRequest request, Model model) {
_logger.info("进入项目管理首页...");
// 获取所有的项目
List<Project> projects = projectService.selectAll();
model.addAttribute("projects", projects);
return "modules/project/projectManagement";
}
/**
* 添加一个项目
* @param project 项目
* @return 项目首页
*/
@RequestMapping(value = "/add", method = RequestMethod.POST)
@RequiresRoles("admin")
public String add(HttpSession session, @ModelAttribute Project project){
_logger.info("添加项目...");
//Thread.sleep(3000L);
projectService.add(project);
// 更新session中的项目数量
int pnum = projectService.selectProjectNum();
session.setAttribute("projectNum", pnum);
return "redirect:/project/index";
}
/**
* 删除一个项目
* @param projectId 项目ID
* @return 项目首页
*/
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
@ResponseBody
@RequiresRoles("admin")
public BaseResponse delete(HttpSession session, @RequestParam("id") Integer projectId) {
_logger.info("删除项目id=" + projectId);
// 项目下存在用户不能删除,该项目下存在用户,无法删除
int userCount = projectService.selectUsersByPrjectId(projectId);
if (userCount > 0) {
return new BaseResponse(false, "该项目下存在用户,无法删除", 0, null);
}
projectService.delete(projectId);
// 更新session中的项目数量
int pnum = projectService.selectProjectNum();
session.setAttribute("projectNum", pnum);
return new BaseResponse(true, "删除项目成功", 0, null);
}
/**
* 上传图片
*
* @return
*/
@RequestMapping(value = "/upload")
@ResponseBody
@RequiresUser
public BaseResponse doPublish(@RequestParam("file") MultipartFile file) {
String fileName0 = toUTF8(file.getOriginalFilename());
String fileName = uuidStr() + fileName0.substring(fileName0.lastIndexOf("."));
_logger.info("Sava fileName=" + fileName);
if (!file.isEmpty()) {
savePic(file, fileName);
return new BaseResponse(true, "上传成功", 0, new FileInfo(fileName));
}
return new BaseResponse(false, "上传失败,因为文件是空的", 0, null);
}
/**
* 获取随机值字符串
* @return
*/
public static String uuidStr() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
private String toUTF8(String str) {
try {
return new String(str.getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
_logger.info("文件名转码错误", e);
}
return null;
}
/**
* 保存图片
* @param picFile
* @param fileName
*/
private void savePic(MultipartFile picFile, String fileName) {
try {
FileUtils.copyInputStreamToFile(picFile.getInputStream(),
new File(myProperties.getPicsPath(), fileName));
} catch (IOException ie) {
ie.printStackTrace();
}
}
}

View File

@ -0,0 +1,149 @@
package com.enzhico.pos.controller;
import com.baomidou.mybatisplus.plugins.Page;
import com.enzhico.pos.common.util.DateUtil;
import com.enzhico.pos.dao.entity.ManagerInfo;
import com.enzhico.pos.dao.entity.SearchUser;
import com.enzhico.pos.model.BaseResponse;
import com.enzhico.pos.service.ManagerInfoService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* Description: 用户管理
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Resource
private ManagerInfoService managerInfoService;
/**
* 用户管理首页
*
* @param request
* @param model
* @return
*/
@RequestMapping(value = "/index")
@RequiresRoles(value = {"admin"})
public String index(HttpServletRequest request, Model model) {
// 查询所有项目列表
model.addAttribute("projects", managerInfoService.allProjects());
return "modules/user/userManagement";
}
/**
* 查询用户列表
*
* @return
*/
@RequestMapping(value = "/list")
@ResponseBody
@RequiresRoles(value = {"admin"})
public BaseResponse list(@ModelAttribute SearchUser searchUser) {
// 创建时间分解
if (StringUtils.isNotEmpty(searchUser.getCreatedTime())) {
String[] ds = searchUser.getCreatedTime().split(" - ");
searchUser.setCreatedTimeStart(DateUtil.getDateStartTime(DateUtil.parseDate(ds[0])));
searchUser.setCreatedTimeEnd(DateUtil.getDateEndTime(DateUtil.parseDate(ds[1])));
}
Page page = new Page(searchUser.getPageNumber(), searchUser.getPageSize());
List<ManagerInfo> list = managerInfoService.searchUsers(page, searchUser);
return new BaseResponse(true, "查询用户列表", page.getTotal(), list);
}
/**
* 用户名重复检查
*
* @return
*/
@RequestMapping(value = "/usernamechk", method = RequestMethod.GET)
@ResponseBody
@RequiresRoles(value = {"admin"})
public BaseResponse doAdd(@RequestParam("username") String username) {
// 用户名重复性检查
int usercount = managerInfoService.checkUsername(username);
if (usercount > 0) {
return new BaseResponse(false, "此用户名已存在", 0, null);
}
return new BaseResponse(true, "此用户名不存在", 0, null);
}
/**
* 执行添加用户
*
* @return
*/
@RequestMapping(value = "/add", method = RequestMethod.POST)
@RequiresRoles(value = {"admin"})
public String doAdd(@ModelAttribute ManagerInfo manager) {
managerInfoService.addUser(manager);
return "redirect:/user/index";
}
/**
* 编辑用户
*
* @param request
* @param model
* @return
*/
@RequestMapping(value = "/edit")
@RequiresRoles(value = {"admin"})
public String edit(HttpServletRequest request, Model model, @RequestParam("id") Integer id) {
// 查询所有项目列表
model.addAttribute("projects", managerInfoService.allProjects());
// 查询用户
model.addAttribute("user", managerInfoService.selectUser(id));
return "modules/user/userEdit :: content";
}
/**
* 执行编辑用户
*
* @return
*/
@RequestMapping(value = "/edit", method = RequestMethod.POST)
@RequiresRoles(value = {"admin"})
public String doEdit(@ModelAttribute ManagerInfo manager) {
managerInfoService.editUser(manager);
return "redirect:/user/index";
}
/**
* 执行重置密码
*
* @return
*/
@RequestMapping(value = "/reset/{id}/{username}", method = RequestMethod.POST)
@RequiresRoles(value = {"admin"})
@ResponseBody
public BaseResponse doReset(@PathVariable("id") Integer id,
@PathVariable("username") String username) {
managerInfoService.resetPassword(id, username);
return new BaseResponse(true, "重置密码成功", 0, null);
}
/**
* 执行删除用户
*
* @return
*/
@RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
@RequiresRoles(value = {"admin"})
@ResponseBody
public BaseResponse doDelete(@PathVariable("id") Integer id) {
managerInfoService.deleteUer(id);
return new BaseResponse(true, "删除用户成功", 0, null);
}
}

View File

@ -0,0 +1,79 @@
package com.enzhico.pos.dao.entity;
import com.enzhico.pos.common.constant.DictMap;
import com.enzhico.pos.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.pos.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.pos.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.pos.dao.entity;
import com.enzhico.pos.common.constant.DictMap;
import com.enzhico.pos.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.pos.dao.entity;
import com.enzhico.pos.common.constant.DictMap;
import com.enzhico.pos.common.dao.entity.Pos;
import com.enzhico.pos.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.pos.dao.entity;
import com.enzhico.pos.common.constant.DictMap;
import com.enzhico.pos.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.pos.dao.entity;
import com.enzhico.pos.common.constant.DictMap;
import com.enzhico.pos.common.dao.entity.Manager;
import com.enzhico.pos.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.pos.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.pos.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.pos.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.pos.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.pos.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.pos.dao.entity;
import com.enzhico.pos.common.dao.entity.Permission;
import com.enzhico.pos.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,47 @@
package com.enzhico.pos.dao.repository;
import com.baomidou.mybatisplus.plugins.pagination.Pagination;
import com.enzhico.pos.common.dao.entity.App;
import com.enzhico.pos.common.dao.entity.Pos;
import com.enzhico.pos.common.dao.repository.AppMapper;
import com.enzhico.pos.dao.entity.AppInfo;
import com.enzhico.pos.dao.entity.AppVersionInfo;
import com.enzhico.pos.dao.entity.SearchApp;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* Description: AppInfoDao
*/
public interface AppInfoDao extends AppMapper {
List<String> selectAllAppNames(List<Integer> pidList);
List<String> selectAllVersions(List<Integer> pidList);
List<String> selectAllLocations(List<Integer> pidList);
List<Pos> selectPosListByLocations(@Param("locations") List<String> locations);
App selectNowVersionApp(@Param("applicationId") String applicationId);
int countUserPermission(@Param("userId") Integer userId, @Param("applicationId") String applicatioinId);
/**
* 分页查询
* @param page
* @param param
* @return
*/
List<AppInfo> searchList(Pagination page, SearchApp param);
/**
* 灰度发布列表
* @param appId
* @return
*/
List<Pos> grayList(@Param("id") Integer appId);
List<AppVersionInfo> selectAppVersionList(List<Integer> pidList);
}

View File

@ -0,0 +1,20 @@
package com.enzhico.pos.dao.repository;
import com.baomidou.mybatisplus.plugins.pagination.Pagination;
import com.enzhico.pos.common.dao.repository.ManagerMapper;
import com.enzhico.pos.dao.entity.ManagerInfo;
import com.enzhico.pos.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,59 @@
package com.enzhico.pos.dao.repository;
import com.baomidou.mybatisplus.plugins.pagination.Pagination;
import com.enzhico.pos.common.dao.entity.PosHistory;
import com.enzhico.pos.common.dao.repository.PosMapper;
import com.enzhico.pos.dao.entity.*;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
/**
* Description :
*/
public interface PosInfoDao extends PosMapper {
/**
* 分页查询
* @param page
* @param param
* @return
*/
List<PosInfo> searchList(Pagination page, SearchPos param);
/**
* 以网点分组进行分页查询
* @param page
* @param param
* @return
*/
List<PosGroupInfo> searchListGroupByLocation(Pagination page, SearchPos param);
PosInfo searchDetail(Integer id);
PosHistory selectLastHistory(@Param("posId") Integer posId,
@Param("location") String location);
/**
* 布放网点数量
* @param projectId
* @return
*/
int searchLocationCount(@Param("projectId") Integer projectId,
@Param("pidList") List<Integer> pidList);
/**
* 网点机具列表分页
* @param searchMonitor
* @return
*/
List<MonitorInfo> selectPosMonitorList(Pagination page, SearchMonitor searchMonitor);
/**
* 更新POS监控在线状态
*
* @param start
* @return
*/
int updateOnlineState(@Param("start") Date start);
}

View File

@ -0,0 +1,13 @@
package com.enzhico.pos.dao.repository;
import com.enzhico.pos.dao.entity.SysRole;
import org.springframework.stereotype.Repository;
/**
* Description :
*/
@Repository
public interface SysRoleDao {
SysRole findByRole(String role);
}

View File

@ -0,0 +1,135 @@
<?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.pos.dao.repository.AppInfoDao">
<resultMap id="AppVersionInfoMap" type="AppVersionInfo">
<result property="appName" column="appName" />
<collection property="versions" ofType="string">
<result column="version"/>
</collection>
</resultMap>
<select id="selectAppVersionList" resultMap="AppVersionInfoMap">
SELECT DISTINCT
A.`name` AS appName,
A.version AS version
FROM t_app A
<where>
A.project_id IN
<foreach collection="list" index="index" item="i" open="(" separator="," close=")">
#{i}
</foreach>
</where>
</select>
<select id="selectAllAppNames" resultType="string">
SELECT DISTINCT name FROM t_app
<where>
project_id IN
<foreach collection="list" index="index" item="i" open="(" separator="," close=")">
#{i}
</foreach>
</where>
</select>
<select id="selectAllVersions" resultType="string">
SELECT DISTINCT version FROM t_app
<where>
project_id IN
<foreach collection="list" index="index" item="i" open="(" separator="," close=")">
#{i}
</foreach>
</where>
</select>
<select id="selectNowVersionApp" resultType="app">
SELECT A.id AS id, A.version AS version
FROM t_app A
WHERE A.publishtime = (SELECT MAX(publishtime) FROM t_app WHERE application_id=#{applicationId})
LIMIT 1
</select>
<select id="countUserPermission" resultType="int">
SELECT COUNT(*)
FROM t_project_user A
LEFT OUTER JOIN t_project B ON A.project_id=B.id
WHERE A.user_id=#{userId} AND B.application_id=#{applicationId}
</select>
<select id="selectAllLocations" resultType="string">
SELECT DISTINCT location FROM t_pos
<where>
project_id IN
<foreach collection="list" index="index" item="i" open="(" separator="," close=")">
#{i}
</foreach>
</where>
</select>
<select id="selectPosListByLocations" resultType="pos">
SELECT DISTINCT
id AS id,
imei AS imei,
location AS location
FROM t_pos
<where>
<if test='locations != null'>
location IN
<foreach collection="locations" index="index" item="i" open="(" separator="," close=")">
#{i}
</foreach>
</if>
</where>
</select>
<select id="searchList" parameterType="searchApp" resultType="appInfo" >
SELECT DISTINCT
A.id AS id,
A.name AS name,
A.version AS version,
A.tips AS tips,
A.publishtime AS publishtime,
A.publish_range AS publishRange,
B.name AS projectName,
C.username AS operatorUsername,
C.name AS operatorName
FROM t_app A
LEFT OUTER JOIN t_project B ON A.project_id=B.id
LEFT OUTER JOIN t_manager C ON A.operator_id=C.id
<where>
A.project_id IN
<foreach collection="pidList" index="index" item="i" open="(" separator="," close=")">
#{i}
</foreach>
<if test='appName != null and appName != ""'>
AND A.name = #{appName}
</if>
<if test='appVersion != null and appVersion != ""'>
AND A.version = #{appVersion}
</if>
<if test='projectId != null and projectId != 0'>
AND A.project_id = #{projectId}
</if>
<if test='publishRange != null and publishRange != 0'>
AND A.publish_range = #{publishRange}
</if>
<if test='publishTimeStart != null and publishTimeEnd != null'>
AND A.publishtime BETWEEN #{publishTimeStart} AND #{publishTimeEnd}
</if>
</where>
ORDER BY A.publishtime DESC
</select>
<select id="grayList" parameterType="int" resultType="pos">
SELECT DISTINCT
A.id AS id,
A.imei AS imei,
A.location AS location
FROM t_pos A
LEFT OUTER JOIN t_app_publish B ON A.id=B.pos_id
LEFT OUTER JOIN t_app C ON B.app_id=C.id
WHERE C.id=#{id}
</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.pos.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,149 @@
<?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.pos.dao.repository.PosInfoDao">
<select id="searchList" parameterType="searchPos" resultType="posInfo">
SELECT DISTINCT
A.id AS id,
A.imei AS imei,
A.series AS series,
A.jointime AS jointime,
A.location AS location,
A.pos_state AS posState,
A.tips AS tips,
B.name AS projectName
FROM t_pos A
LEFT OUTER JOIN t_project B ON A.project_id=B.id
<where>
A.project_id IN
<foreach collection="pidList" index="index" item="i" open="(" separator="," close=")">
#{i}
</foreach>
<if test='imei != null and imei != ""'>
AND A.imei = #{imei}
</if>
<if test='location != null and location != ""'>
AND A.location = #{location}
</if>
<if test='projectId != null and projectId != 0'>
AND A.project_id = #{projectId}
</if>
</where>
ORDER BY A.jointime DESC
</select>
<select id="searchDetail" parameterType="int" resultType="posInfo">
SELECT DISTINCT
A.id AS id,
A.imei AS imei,
A.sn AS sn,
A.series AS series,
A.android_version AS androidVersion,
A.version AS version,
A.owner AS owner,
A.jointime AS jointime,
A.bindtime AS bindtime,
A.location AS location,
A.pos_state AS posState,
A.tips AS tips,
B.name AS projectName
FROM t_pos A
LEFT OUTER JOIN t_project B ON A.project_id=B.id
WHERE A.id=#{id}
</select>
<select id="selectLastHistory" resultType="posHistory">
SELECT
id AS id,
pos_id AS posId,
location AS location,
bindtime AS bindtime,
unbindtime AS unbindtime,
created_time AS createdTime
FROM t_pos_history
WHERE pos_id=#{posId} AND location=#{location} AND unbindtime IS NULL
AND created_time = (SELECT MAX(created_time) FROM t_pos_history WHERE pos_id=#{posId})
LIMIT 1
</select>
<!-- 查询网点数量-->
<select id="searchLocationCount" parameterType="int" resultType="int">
SELECT COUNT(DISTINCT location)
FROM t_pos
<where>
location &lt;&gt; ''
<if test='projectId != null and projectId != 0'>
AND project_id = #{projectId}
</if>
<if test='projectId == null or projectId == 0'>
AND project_id IN
<foreach collection="pidList" index="index" item="i" open="(" separator="," close=")">
#{i}
</foreach>
</if>
</where>
</select>
<!-- 已网点分组查询机具列表-->
<select id="searchListGroupByLocation" parameterType="searchPos" resultType="posGroupInfo" >
SELECT
A.location AS location,
B.name AS projectName,
COUNT(*) AS posCount
FROM t_pos A
LEFT OUTER JOIN t_project B ON A.project_id=B.id
<where>
A.location &lt;&gt; ''
AND A.project_id IN
<foreach collection="pidList" index="index" item="i" open="(" separator="," close=")">
#{i}
</foreach>
<if test='projectId != null and projectId != 0'>
AND A.project_id = #{projectId}
</if>
<if test='location != null and location != ""'>
AND A.location = #{location}
</if>
</where>
GROUP BY A.location, B.name
</select>
<!-- 每个网点的机具监控列表-->
<select id="selectPosMonitorList" parameterType="searchMonitor" resultType="monitorInfo">
SELECT
A.id AS id,
A.report_time AS reportTime,
A.report_location AS reportLocation,
A.online_state AS onlineState,
B.imei AS imei,
B.series AS series
FROM
t_pos_monitor A
LEFT OUTER JOIN t_pos B ON A.pos_id=B.id
<where>
B.location &lt;&gt; ''
<if test='imei != null and imei != ""'>
AND B.imei = #{imei}
</if>
<if test='location != null and location != ""'>
AND B.location = #{location}
</if>
AND B.project_id IN
<foreach collection="pidList" index="index" item="i" open="(" separator="," close=")">
#{i}
</foreach>
<if test='projectId != null and projectId != 0'>
AND B.project_id = #{projectId}
</if>
<if test='onlineState != null and onlineState != 0'>
AND A.online_state = #{onlineState}
</if>
</where>
ORDER BY A.report_time DESC
</select>
<!-- 更新长期没有报告的POS状态为离线-->
<update id="updateOnlineState">
UPDATE t_pos_monitor SET online_state=2 WHERE report_time &lt; #{start}
</update>
</mapper>

View File

@ -0,0 +1,6 @@
<?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.pos.dao.repository.SysRoleDao">
</mapper>

View File

@ -0,0 +1,14 @@
package com.enzhico.pos.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,20 @@
package com.enzhico.pos.http;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.DefaultResponseErrorHandler;
import java.io.IOException;
/**
* RestTemplate自定义异常处理
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/24
*/
public class CustomResponseErrorHandler extends DefaultResponseErrorHandler {
@Override
public void handleError(ClientHttpResponse response) throws IOException {
super.handleError(response);
}
}

View File

@ -0,0 +1,60 @@
package com.enzhico.pos.http;
/**
* API接口的基础返回类
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/7
*/
public class HttpBaseResponse<T> {
/**
* 是否成功
*/
private boolean success;
/**
* 说明
*/
private String msg;
/**
* 返回数据
*/
private T data;
public HttpBaseResponse() {
}
public HttpBaseResponse(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,59 @@
package com.enzhico.pos.http;
/**
* 登录认证接口参数
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/9
*/
public class LoginParam {
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* Application ID
*/
private String appid;
/**
* IMEI码
*/
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,32 @@
package com.enzhico.pos.http;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import java.io.IOException;
/**
* TokenRequestInterceptor
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/23
*/
public class TokenRequestInterceptor implements ClientHttpRequestInterceptor {
private String token;
public TokenRequestInterceptor(String token) {
this.token = token;
}
@Override
public ClientHttpResponse intercept(
HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpHeaders headers = request.getHeaders();
headers.add("Authorization", token);
return execution.execute(request, body);
}
}

View File

@ -0,0 +1,35 @@
package com.enzhico.pos.http;
/**
* 解绑通知参数
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/9
*/
public class UnbindParam {
/**
* IMEI码
*/
private String imei;
/**
* 网点
*/
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.pos.jobs;
import com.enzhico.pos.service.MonitorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 银企直联查账的定时任务
*
* 第一位表示秒取值0-59
* 第二位表示分取值0-59
* 第三位表示小时取值0-23
* 第四位,日期天/日取值1-31
* 第五位日期月份取值1-12
* 第六位星期取值1-71表示星期天2表示星期一
* 第七位年份可以留空取值1970-2099
*
* @author XiongNeng
* @version 1.0
* @since 2017/9/27
*/
@Component
public class HeartbeatJob {
private static final Logger logger = LoggerFactory.getLogger(HeartbeatJob.class);
@Resource
private MonitorService monitorService;
// /**
// * 中午12:30上传检查
// */
// @Scheduled(cron = "0 35 12 * * ?")
// public void checkState1() {
// logger.info(">>>>> cron中午12:30上传检查开始....");
// monitorService.updateOnlineState();
// logger.info(">>>>> cron中午12:30上传检查完成....");
// }
//
// /**
// * 晚上18:00上传检查
// */
// @Scheduled(cron = "0 05 18 * * ?")
// public void checkState2() {
// logger.info(">>>>> cron晚上18:00上传检查开始....");
// monitorService.updateOnlineState();
// logger.info(">>>>> cron晚上18:00上传检查完成....");
// }
}

View File

@ -0,0 +1,73 @@
package com.enzhico.pos.model;
/**
* Controller的基础返回类
*
* @author XiongNeng
* @version 1.0
* @since 2018/1/7
*/
public class BaseResponse<T> {
/**
* 是否成功
*/
private boolean success;
/**
* 说明
*/
private String msg;
/**
* 返回数据
*/
private T data;
/**
* 分页时候的总数
*/
private Integer total;
public BaseResponse() {
}
public BaseResponse(boolean success, String msg, Integer total, T data) {
this.success = success;
this.msg = msg;
this.total = total;
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;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
}

View File

@ -0,0 +1,215 @@
package com.enzhico.pos.service;
import com.baomidou.mybatisplus.mapper.Condition;
import com.baomidou.mybatisplus.plugins.Page;
import com.enzhico.pos.common.dao.entity.*;
import com.enzhico.pos.common.dao.repository.AppPublishMapper;
import com.enzhico.pos.common.dao.repository.PosMapper;
import com.enzhico.pos.common.dao.repository.ProjectMapper;
import com.enzhico.pos.common.util.CommonUtil;
import com.enzhico.pos.config.properties.MyProperties;
import com.enzhico.pos.dao.entity.*;
import com.enzhico.pos.dao.repository.AppInfoDao;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* App管理Service
*/
@Service
public class AppService {
@Resource
private AppInfoDao appInfoDao;
@Resource
private PosMapper posMapper;
@Resource
private AppPublishMapper appPublishMapper;
@Resource
private ProjectMapper projectMapper;
@Resource
private MyProperties myProperties;
/**
* 查询所有应用名称
* @param pidList 用户所属项目ID
* @return 所有应用名称
*/
public List<String> selectAllAppNames(List<Integer> pidList) {
return appInfoDao.selectAllAppNames(pidList);
}
/**
* 应用名称与版本号的对应关系
* @param pidList 用户所属项目ID
* @return 应用名称与版本号的对应关系
*/
public Map<String, List<String>> selectAppVersionList(List<Integer> pidList) {
List<AppVersionInfo> list = appInfoDao.selectAppVersionList(pidList);
Map<String, List<String>> map = new HashMap<>();
if (list != null) {
for (AppVersionInfo appVersionInfo : list) {
map.put(appVersionInfo.getAppName(), appVersionInfo.getVersions());
}
}
return map;
}
/**
* 查询所有版本号
* @param pidList 用户所属项目ID
* @return 所有版本号
*/
public List<String> selectAllVersions(List<Integer> pidList) {
return appInfoDao.selectAllVersions(pidList);
}
/**
* 查询所有项目
* @param pidList 用户所属项目ID
* @return
*/
public List<Project> selectAllProjects(List<Integer> pidList) {
return projectMapper.selectList(Condition.create().in("id", pidList));
}
/**
* 查询所有网点
* @param pidList 用户所属项目ID
* @return
*/
public List<String> selectAllLocations(List<Integer> pidList) {
return appInfoDao.selectAllLocations(pidList);
}
/**
* 根据网点列表查询Pos机
* @param locations
* @return
*/
public List<Pos> selectPosListByLocations(List<String> locations) {
return appInfoDao.selectPosListByLocations(locations);
}
/**
* 分页查询
* @param page
* @param searchApp
* @return
*/
public List<AppInfo> searchList(Page<AppInfo> page, SearchApp searchApp) {
List<AppInfo> list = appInfoDao.searchList(page, searchApp);
for (AppInfo appInfo : list) {
appInfo.buildTable();
appInfo.setDownloadUrl(myProperties.getFilesUrlPrefix()
+ appInfo.getName() + "_" + appInfo.getVersion() + ".apk");
}
return list;
}
/**
* 灰度发布查询
* @return
*/
public List<Pos> grayList(Integer appId) {
return appInfoDao.grayList(appId);
}
/**
* 根据imei查询POS
* @param imei
* @return
*/
public Pos selectByImei(String imei) {
Pos p = new Pos();
p.setImei(imei);
return posMapper.selectOne(p);
}
/**
* 全网发布
* @param appId
*/
public void publishAll(Integer appId) {
// 先删除灰度发布记录
appPublishMapper.delete(Condition.create().eq("app_id", appId));
// 然后更新App
App app = new App();
app.setPublishRange(1);
app.setUpdatedTime(new Date());
app.setId(appId);
appInfoDao.updateById(app);
}
/**
* 用户发布权限检查
* @param userId 登录用户ID
* @param applicationId 应用ID
* @return 是否有权限发布
*/
public boolean checkUserPublishPermission(Integer userId, String applicationId) {
return appInfoDao.countUserPermission(userId, applicationId) > 0;
}
/**
* 检查版本号的合法性,只能升版本发布
* @param applicationId APP唯一标识
* @param version 版本号
* @return 版本号是否更高
*/
public boolean checkAppVersion(String applicationId, String version) {
// 先检查是否存在至少一个APP记录
int appCount = appInfoDao.selectCount(Condition.create().eq("application_id", applicationId));
if (appCount == 0) {
return true;
}
App nowApp = appInfoDao.selectNowVersionApp(applicationId);
if (nowApp == null) {
throw new NullPointerException();
}
return CommonUtil.isNewer(version, nowApp.getVersion());
}
/**
* 添加新版本
*/
public void addVersion(PublishParam param, ManagerInfo manager) {
// 通过application Id获取Project
Project p = new Project();
p.setApplicationId(param.getApplicationId());
Project project = projectMapper.selectOne(p);
// 新建APP
App app = new App();
app.setName(param.getName());
app.setVersion(param.getVersion());
app.setApplicationId(param.getApplicationId());
app.setProjectId(project.getId());
app.setTips(param.getTips());
Date now = new Date();
app.setPublishtime(now);
app.setPublishRange(param.getPublishRange());
app.setOperatorId(manager.getId());
appInfoDao.insert(app);
// 如果是灰度发布则更新APP发布表
if (param.getPublishRange() == 2 && StringUtils.isNotEmpty(param.getGrayIds())) {
String grayIds = param.getGrayIds();
for (String posId : grayIds.split(",")) {
AppPublish appPublish = new AppPublish();
appPublish.setAppId(app.getId());
appPublish.setPosId(Integer.valueOf(posId));
appPublishMapper.insert(appPublish);
}
}
}
}

View File

@ -0,0 +1,149 @@
package com.enzhico.pos.service;
import com.baomidou.mybatisplus.mapper.Condition;
import com.baomidou.mybatisplus.plugins.Page;
import com.enzhico.pos.async.AsyncException;
import com.enzhico.pos.async.AsyncTask;
import com.enzhico.pos.common.dao.entity.Pos;
import com.enzhico.pos.common.dao.entity.PosHistory;
import com.enzhico.pos.common.dao.entity.Project;
import com.enzhico.pos.common.dao.repository.PosHistoryMapper;
import com.enzhico.pos.common.dao.repository.ProjectMapper;
import com.enzhico.pos.config.properties.MyProperties;
import com.enzhico.pos.dao.entity.ManagerInfo;
import com.enzhico.pos.dao.entity.PosInfo;
import com.enzhico.pos.dao.entity.SearchPos;
import com.enzhico.pos.dao.repository.PosInfoDao;
import com.enzhico.pos.http.HttpBaseResponse;
import com.enzhico.pos.http.LoginParam;
import com.enzhico.pos.http.TokenRequestInterceptor;
import com.enzhico.pos.http.UnbindParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Date;
import java.util.List;
/**
* 机具管理Service
*/
@Service
public class DeviceService {
private static final Logger logger = LoggerFactory.getLogger(DeviceService.class);
@Resource
private PosInfoDao posInfoDao;
@Resource
private ProjectMapper projectMapper;
@Resource
private PosHistoryMapper posHistoryMapper;
@Resource
private AsyncTask asyncTask;
/**
* 所有项目列表
*
* @return 查询到的所有项目列表
*/
public List<Project> allProjects(List<Integer> pidList) {
return projectMapper.selectList(Condition.create().in("id", pidList));
}
/**
* 分页查询
*
* @param page 分页参数
* @param searchPos 查询条件
* @return 分页结果
*/
public List<PosInfo> searchList(Page<PosInfo> page, SearchPos searchPos) {
List<PosInfo> list = posInfoDao.searchList(page, searchPos);
for (PosInfo posInfo : list) {
posInfo.buildTable();
}
return list;
}
/**
* 查询机具详情
*
* @param id 机具ID
* @return 查询的POS详情
*/
public PosInfo searchDetail(Integer id) {
PosInfo posInfo = posInfoDao.searchDetail(id);
posInfo.buildTable();
return posInfo;
}
/**
* 更新机具状态
*
* @param id 机具ID
* @param state 状态值
* @return 更新结果
*/
public int updateState(Integer id, Integer state) {
Pos pos = new Pos();
pos.setId(id);
pos.setPosState(state);
pos.setUpdatedTime(new Date());
return posInfoDao.updateById(pos);
}
/**
* 解除绑定
*
* @param id pos机的ID
* @return 解绑结果
*/
public int unbind(Integer id, ManagerInfo managerInfo) {
Date now = new Date();
Pos pos = posInfoDao.selectById(id);
// 先保存网点
String location = pos.getLocation();
pos.setLocation("");
pos.setUpdatedTime(now);
posInfoDao.updateById(pos);
// 解绑之后更新绑定历史
PosHistory posHistory = posInfoDao.selectLastHistory(id, location);
if (posHistory != null) {
posHistory.setUnbindtime(now);
posHistory.setUpdatedTime(now);
posHistoryMapper.updateById(posHistory);
}
// 开始异步推送消息
asyncTask.pushUnbindMsg(managerInfo, pos, location);
return 1;
}
/**
* 查询pos绑定历史列表
*
* @param posId 机具ID
* @return 绑定历史列表,按照绑定事件倒叙排列
*/
public List<PosHistory> selectHisotryList(Integer posId) {
return posHistoryMapper.selectList(Condition.create().eq("pos_id", posId).orderBy("bindtime", false));
}
}

View File

@ -0,0 +1,193 @@
package com.enzhico.pos.service;
import com.baomidou.mybatisplus.mapper.Condition;
import com.baomidou.mybatisplus.plugins.Page;
import com.enzhico.pos.common.dao.entity.Manager;
import com.enzhico.pos.common.dao.entity.Project;
import com.enzhico.pos.common.dao.entity.ProjectUser;
import com.enzhico.pos.common.dao.repository.ProjectMapper;
import com.enzhico.pos.common.dao.repository.ProjectUserMapper;
import com.enzhico.pos.dao.entity.ManagerInfo;
import com.enzhico.pos.dao.entity.SearchUser;
import com.enzhico.pos.dao.repository.ManagerInfoDao;
import com.enzhico.pos.exception.ForbiddenUserException;
import com.enzhico.pos.shiro.ShiroKit;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.crypto.hash.SimpleHash;
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,95 @@
package com.enzhico.pos.service;
import com.baomidou.mybatisplus.mapper.Condition;
import com.baomidou.mybatisplus.plugins.Page;
import com.enzhico.pos.common.dao.entity.Project;
import com.enzhico.pos.common.dao.repository.ProjectMapper;
import com.enzhico.pos.common.util.DateUtil;
import com.enzhico.pos.config.properties.MyProperties;
import com.enzhico.pos.dao.entity.*;
import com.enzhico.pos.dao.repository.PosInfoDao;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
* 监控管理Service
*/
@Service
public class MonitorService {
@Resource
private ProjectMapper projectMapper;
@Resource
private PosInfoDao posInfoDao;
@Resource
private MyProperties myProperties;
/**
* 查询所有项目
* @return
*/
public List<Project> selectAllProjects(List<Integer> pidList) {
return projectMapper.selectList(Condition.create().in("id", pidList));
}
/**
* 入网机具总数
* @return
*/
public int posCount(Integer projectId, List<Integer> pidList) {
if (projectId != 0) {
return posInfoDao.selectCount(
Condition.create().eq("project_id", projectId).ne("location", ""));
}
return posInfoDao.selectCount(Condition.create().ne("location", "").in("project_id", pidList));
}
/**
* 布放网点数
* @param projectId
* @return
*/
public int locationCount(Integer projectId, List<Integer> pidList) {
return posInfoDao.searchLocationCount(projectId, pidList);
}
/**
* 分页查询,以网点分组
* @param page
* @param searchPos
* @return
*/
public List<PosGroupInfo> searchListGroupByLocation(Page<PosInfo> page, SearchPos searchPos) {
List<PosGroupInfo> list = posInfoDao.searchListGroupByLocation(page, searchPos);
return list;
}
/**
* 网点详细页面分页查询
* @param page
* @param searchMonitor
* @return
*/
public List<MonitorInfo> searchLocationMonitorList(Page<PosInfo> page, SearchMonitor searchMonitor) {
List<MonitorInfo> list = posInfoDao.selectPosMonitorList(page, searchMonitor);
if (list != null) {
for (MonitorInfo monitorInfo : list) {
monitorInfo.buildTable();
}
}
return list;
}
/**
* 定期更新在线状态
*/
public void updateOnlineState() {
posInfoDao.updateOnlineState(DateUtil.offsiteDate(new Date(), Calendar.MINUTE, -10));
}
}

View File

@ -0,0 +1,94 @@
package com.enzhico.pos.service;
import com.baomidou.mybatisplus.mapper.Condition;
import com.enzhico.pos.common.dao.entity.App;
import com.enzhico.pos.common.dao.entity.Pos;
import com.enzhico.pos.common.dao.entity.Project;
import com.enzhico.pos.common.dao.entity.ProjectUser;
import com.enzhico.pos.common.dao.repository.AppMapper;
import com.enzhico.pos.common.dao.repository.PosMapper;
import com.enzhico.pos.common.dao.repository.ProjectMapper;
import com.enzhico.pos.common.dao.repository.ProjectUserMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/**
* 项目管理Service
*/
@Service
public class ProjectService {
@Resource
private ProjectMapper projectMapper;
@Resource
private ProjectUserMapper projectUserMapper;
@Resource
protected PosMapper posMapper;
@Resource
private AppMapper appMapper;
/**
* 查询所有项目的数量
* @return 项目的数量
*/
public int selectProjectNum() {
return projectMapper.selectCount(null);
}
/**
* 查询该项目下所有用户数量
* @return
*/
public int selectUsersByPrjectId(Integer projectId) {
return projectUserMapper.selectCount(Condition.create().eq("project_id", projectId));
}
/**
* 查询所有项目
* @return 所有项目
*/
public List<Project> selectAll() {
return projectMapper.selectList(null);
}
/**
* 添加项目
* @param project 项目
* @return 结果
*/
public int add(Project project) {
return projectMapper.insert(project);
}
/**
* 删除项目
* @param id 项目ID
* @return 结果
*/
public int delete(Integer id) {
// 先删项目表
projectMapper.deleteById(id);
// 删项目用户关联表记录
projectUserMapper.delete(Condition.create().eq("project_id", id));
// 更新pos机记录
Pos pos = new Pos();
pos.setProjectId(0);
Date now = new Date();
pos.setUpdatedTime(now);
posMapper.update(pos, Condition.create().eq("project_id", id));
// 更新App表记录
App app = new App();
app.setProjectId(0);
app.setUpdatedTime(now);
appMapper.update(app, Condition.create().eq("project_id", id));
return 1;
}
}

View File

@ -0,0 +1,29 @@
package com.enzhico.pos.shiro;
import org.apache.shiro.authc.UsernamePasswordToken;
/**
* Description : 拓展登陆验证字段
*/
public class CaptchaUsernamePasswordToken extends UsernamePasswordToken {
private static final long serialVersionUID = 1L;
//验证码字符串
private String captcha;
public CaptchaUsernamePasswordToken(String username, char[] password,
boolean rememberMe, String host, String captcha) {
super(username, password, rememberMe, host);
this.captcha = captcha;
}
public String getCaptcha() {
return captcha;
}
public void setCaptcha(String captcha) {
this.captcha = captcha;
}
}

View File

@ -0,0 +1,28 @@
package com.enzhico.pos.shiro;
import org.apache.shiro.authc.AuthenticationException;
/**
* Description : 验证码错误异常
*/
public class IncorrectCaptchaException extends AuthenticationException {
private static final long serialVersionUID = 1L;
public IncorrectCaptchaException() {
super();
}
public IncorrectCaptchaException(String message, Throwable cause) {
super(message, cause);
}
public IncorrectCaptchaException(String message) {
super(message);
}
public IncorrectCaptchaException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,107 @@
package com.enzhico.pos.shiro;
import com.enzhico.pos.dao.entity.ManagerInfo;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
/**
* Description: 验证码过滤器此过滤器已经在shiro中配置这里不需要再次配置拦截路径
*/
public class KaptchaFilter extends FormAuthenticationFilter {
public static final String DEFAULT_CAPTCHA_PARAM = "captcha";
private String captchaParam = DEFAULT_CAPTCHA_PARAM;
private static final Logger _logger = LoggerFactory.getLogger(KaptchaFilter.class);
//登录验证
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response)
throws Exception {
CaptchaUsernamePasswordToken token = createToken(request, response);
try {
_logger.info("KaptchaFilter.executeLogin");
/*图形验证码验证*/
doCaptchaValidate((HttpServletRequest) request, token);
Subject subject = getSubject(request, response);
subject.login(token);//正常验证
//到这里就算验证成功了,把用户信息放到session中
ManagerInfo user = ShiroKit.getUser();
((HttpServletRequest) request).getSession().setAttribute("user", user);
return onLoginSuccess(token, subject, request, response);
} catch (AuthenticationException e) {
return onLoginFailure(token, e, request, response);
}
}
@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject,
ServletRequest request, ServletResponse response) throws Exception {
issueSuccessRedirect(request, response);
//we handled the success redirect directly, prevent the chain from continuing:
return false;
}
protected void issueSuccessRedirect(ServletRequest request, ServletResponse response) throws Exception {
WebUtils.issueRedirect(request, response, "/", null, true);
}
// 验证码校验
protected void doCaptchaValidate(HttpServletRequest request, CaptchaUsernamePasswordToken token) {
_logger.info("KaptchaFilter.doCaptchaValidate");
//session中的图形码字符串
String captcha = (String) request.getSession().getAttribute(
com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
_logger.info("session中的图形码字符串:" + captcha);
//比对
if (captcha == null || !captcha.equalsIgnoreCase(token.getCaptcha())) {
throw new IncorrectCaptchaException();
}
}
@Override
protected CaptchaUsernamePasswordToken createToken(ServletRequest request, ServletResponse response) {
String username = getUsername(request);
String password = getPassword(request);
String captcha = getCaptcha(request);
boolean rememberMe = isRememberMe(request);
String host = getHost(request);
return new CaptchaUsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha);
}
public String getCaptchaParam() {
return captchaParam;
}
public void setCaptchaParam(String captchaParam) {
this.captchaParam = captchaParam;
}
protected String getCaptcha(ServletRequest request) {
return WebUtils.getCleanParam(request, getCaptchaParam());
}
//保存异常对象到request
@Override
protected void setFailureAttribute(ServletRequest request, AuthenticationException ae) {
request.setAttribute(getFailureKeyAttribute(), ae);
}
}

View File

@ -0,0 +1,24 @@
package com.enzhico.pos.shiro;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Description : 自定义异常处理类
*/
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//如果是shiro无权操作因为shiro 在操作auno等一部分不进行转发至无权限url
if (ex instanceof UnauthorizedException) {
return new ModelAndView("error/shiro_403");
}
return null;
}
}

View File

@ -0,0 +1,126 @@
package com.enzhico.pos.shiro;
import com.enzhico.pos.common.dao.entity.Permission;
import com.enzhico.pos.service.ManagerInfoService;
import com.enzhico.pos.dao.entity.ManagerInfo;
import com.enzhico.pos.dao.entity.SysRole;
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.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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.apache.shiro.util.ByteSource;
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;
/**
* 认证信息.(身份验证)
* Authentication 是用来验证用户身份
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
_logger.info("MyShiroRealm.doGetAuthenticationInfo()");
//获取用户的输入的账号.
String username = (String) token.getPrincipal();
//_logger.info("用户的账号:"+username);
//通过username从数据库中查找 ManagerInfo对象
//实际项目中这里可以根据实际情况做缓存如果不做Shiro自己也是有时间间隔机制2分钟内不会重复执行该方法
ManagerInfo managerInfo = managerInfoService.findByUsername(username);
if (managerInfo == null) {
return null;
}
//交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配如果觉得人家的不好可以自定义实现
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
managerInfo, //用户
managerInfo.getPassword(), //密码
ByteSource.Util.bytes(managerInfo.getCredentialsSalt()),//salt=username+salt
getName() //realm name
);
//明文: 若存在将此用户存放到登录认证info中无需自己做密码对比Shiro会为我们进行密码对比校验
// SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
// managerInfo, //用户名
// managerInfo.getPassword(), //密码
// getName() //realm name
// );
return authenticationInfo;
}
/**
* 此方法调用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()");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
ManagerInfo managerInfo = (ManagerInfo) principals.getPrimaryPrincipal();
//设置相应角色的权限信息
for (SysRole role : managerInfo.getRoles()) {
//设置角色
authorizationInfo.addRole(role.getRole());
for (Permission p : role.getPermissions()) {
//设置权限
authorizationInfo.addStringPermission(p.getPermission());
}
}
return authorizationInfo;
}
/**
* 设置认证加密方式
*/
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
HashedCredentialsMatcher md5CredentialsMatcher = new HashedCredentialsMatcher();
md5CredentialsMatcher.setHashAlgorithmName(ShiroKit.HASH_ALGORITHM_NAME);
md5CredentialsMatcher.setHashIterations(ShiroKit.HASH_ITERATIONS);
super.setCredentialsMatcher(md5CredentialsMatcher);
}
}

View File

@ -0,0 +1,32 @@
package com.enzhico.pos.shiro;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
/**
* Description : 角色过滤器,为了实现or的效果就使用这个过滤器,shiro默认是and的效果
*/
public class RoleFilter extends RolesAuthorizationFilter {
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
throws IOException {
Subject subject = getSubject(request, response);
String[] rolesArray = (String[]) mappedValue;
if (rolesArray == null || rolesArray.length == 0) {
return true;
}
for (int i = 0; i < rolesArray.length; i++) {
if (subject.hasRole(rolesArray[i])) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,252 @@
/**
* 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.pos.shiro;
import com.enzhico.pos.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();
}
/**
* 获取封装的 ShiroUser
*
* @return ShiroUser
*/
public static ManagerInfo getUser() {
if (isGuest()) {
return null;
} else {
return (ManagerInfo) getSubject().getPrincipals().getPrimaryPrincipal();
}
}
/**
* 从shiro获取session
*/
public static Session getSession() {
return getSubject().getSession();
}
/**
* 获取shiro指定的sessionKey
*/
@SuppressWarnings("unchecked")
public static <T> T getSessionAttr(String key) {
Session session = getSession();
return session != null ? (T) session.getAttribute(key) : null;
}
/**
* 设置shiro指定的sessionKey
*/
public static void setSessionAttr(String key, Object value) {
Session session = getSession();
session.setAttribute(key, value);
}
/**
* 移除shiro指定的sessionKey
*/
public static void removeSessionAttr(String key) {
Session session = getSession();
if (session != null)
session.removeAttribute(key);
}
/**
* 验证当前用户是否属于该角色?,使用时与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;
}
/**
* 验证当前用户是否属于以下所有角色。
*
* @param roleNames 角色列表
* @return 属于:true,否则false
*/
public static boolean hasAllRoles(String roleNames) {
boolean hasAllRole = true;
Subject subject = getSubject();
if (subject != null && roleNames != null && roleNames.length() > 0) {
for (String role : roleNames.split(NAMES_DELIMETER)) {
if (!subject.hasRole(role.trim())) {
hasAllRole = false;
break;
}
}
}
return hasAllRole;
}
/**
* 验证当前用户是否拥有指定权限,使用时与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,116 @@
##########################################################
################## 所有profile共有的配置 #################
##########################################################
################### 自定义项目配置 ###################
enzhico:
kaptcha-open: true #是否开启登录时验证码 (true/false)
session-open: false #是否开启session验证 (true/false)
session-invalidate-time: 7200 #session失效时间 单位:秒
session-validation-interval: 3600 #多久检测一次失效的session 单位:秒
heartbeat-timeout: 10 # 机具心跳报告超时时间 单位:分钟
################### 项目启动端口 ###################
server.port: 8092
################### spring配置 ###################
spring:
profiles:
active: dev
thymeleaf:
mode: HTML
cache: false
mvc:
view:
prefix: /templates
http:
multipart:
max-request-size: 100MB #最大请求大小
max-file-size: 100MB #最大文件大小
################### mybatis-plus配置 ###################
mybatis-plus:
mapper-locations: classpath*:com/enzhico/pos/dao/repository/mapping/*.xml
typeAliasesPackage: >
com.enzhico.pos.api.model,
com.enzhico.pos.dao.entity,
com.enzhico.pos.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:
excel-path: E:/home/
files-path: E:/home/
files-url-prefix: https://show.enzhico.net/files/ # 文件访问URL前缀
pics-path: E:/home/
pics-url-prefix: https://show.enzhico.net/pics/ # 图片访问URL前缀
posapi-url-prefix: http://123.207.66.156:9095
logging:
level:
ROOT: INFO
com:
enzhico: DEBUG
file: E:/logs/app-manage.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:
excel-path: /var/data/
files-path: /usr/share/nginx/html/files/
files-url-prefix: https://show.enzhico.net/files/ # 文件访问URL前缀
pics-path: /usr/share/nginx/html/pics/
pics-url-prefix: https://show.enzhico.net/pics/ # 图片访问URL前缀
# posapi-url-prefix: http://posapi.enzhico.net
posapi-url-prefix: http://123.207.66.156:9095
logging:
level:
ROOT: INFO
com:
enzhico: DEBUG
file: /var/logs/app-manage.log

View File

@ -0,0 +1,23 @@
_____ _______ _____ _____
/\ \ /::\ \ /\ \ /\ \
/::\____\ /::::\ \ /::\____\ /::\ \
/:::/ / /::::::\ \ /:::/ / /::::\ \
/:::/ / /::::::::\ \ /:::/ / /::::::\ \
/:::/ / /:::/~~\:::\ \ /:::/ / /:::/\:::\ \
/:::/ / /:::/ \:::\ \ /:::/____/ /:::/__\:::\ \
/:::/ / /:::/ / \:::\ \ |::| | /::::\ \:::\ \
/:::/ / /:::/____/ \:::\____\ |::| | _____ /::::::\ \:::\ \
/:::/ / |:::| | |:::| | |::| | /\ \ /:::/\:::\ \:::\ \
/:::/____/ |:::|____| |:::| | |::| | /::\____\/:::/__\:::\ \:::\____\
\:::\ \ \:::\ \ /:::/ / |::| | /:::/ /\:::\ \:::\ \::/ /
\:::\ \ \:::\ \ /:::/ / |::| | /:::/ / \:::\ \:::\ \/____/
\:::\ \ \:::\ /:::/ / |::|____|/:::/ / \:::\ \:::\ \
\:::\ \ \:::\__/:::/ / |:::::::::::/ / \:::\ \:::\____\
\:::\ \ \::::::::/ / \::::::::::/____/ \:::\ \::/ /
\:::\ \ \::::::/ / ~~~~~~~~~~ \:::\ \/____/
\:::\ \ \::::/ / \:::\ \
\:::\____\ \::/____/ \:::\____\
\::/ / ~~ \::/ /
\/____/ \/____/

View File

@ -0,0 +1,83 @@
<?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="CONSTANT"
maxElementsInMemory="50000"
eternal="true"
clearOnFlush="false"
overflowToDisk="true"
diskSpoolBufferSizeMB="1024"
maxElementsOnDisk="100000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
</cache>
<cache name="TOKEN_CACHE"
maxElementsInMemory="50000"
eternal="true"
clearOnFlush="false"
overflowToDisk="true"
diskSpoolBufferSizeMB="1024"
maxElementsOnDisk="100000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
</cache>
<cache name="shiro-activeSessionCache"
maxElementsInMemory="10000"
overflowToDisk="true"
eternal="true"
timeToLiveSeconds="0"
timeToIdleSeconds="0"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="600"/>
<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"
-->

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,36 @@
body, div {
margin: 0;
padding: 0;
}
body {
background: url("../img/error/error_bg.jpg") repeat-x scroll 0 0 #67ACE4;
}
#container {
margin: 0 auto;
padding-top: 50px;
text-align: center;
width: 560px;
}
#container img {
border: medium none;
margin-bottom: 50px;
}
#container .error {
height: 200px;
position: relative;
}
#container .error img {
bottom: -50px;
position: absolute;
right: -50px;
}
#container .msg {
margin-bottom: 65px;
}
#cloud {
background: url("../img/error/error_cloud.png") repeat-x scroll 0 0 transparent;
bottom: 0;
height: 170px;
position: absolute;
width: 100%;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,313 @@
/**
* @author zhixin wen <wenzhixin2010@gmail.com>
* version: 1.11.1
* https://github.com/wenzhixin/bootstrap-table/
*/
.bootstrap-table .table {
margin-bottom: 0 !important;
border-bottom: 1px solid #dddddd;
border-collapse: collapse !important;
border-radius: 1px;
}
.bootstrap-table .table:not(.table-condensed),
.bootstrap-table .table:not(.table-condensed) > tbody > tr > th,
.bootstrap-table .table:not(.table-condensed) > tfoot > tr > th,
.bootstrap-table .table:not(.table-condensed) > thead > tr > td,
.bootstrap-table .table:not(.table-condensed) > tbody > tr > td,
.bootstrap-table .table:not(.table-condensed) > tfoot > tr > td {
padding: 8px;
}
.bootstrap-table .table.table-no-bordered > thead > tr > th,
.bootstrap-table .table.table-no-bordered > tbody > tr > td {
border-right: 2px solid transparent;
}
.bootstrap-table .table.table-no-bordered > tbody > tr > td:last-child {
border-right: none;
}
.fixed-table-container {
position: relative;
clear: both;
border: 1px solid #dddddd;
border-radius: 4px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
}
.fixed-table-container.table-no-bordered {
border: 1px solid transparent;
}
.fixed-table-footer,
.fixed-table-header {
overflow: hidden;
}
.fixed-table-footer {
border-top: 1px solid #dddddd;
}
.fixed-table-body {
overflow-x: auto;
overflow-y: auto;
height: 100%;
}
.fixed-table-container table {
width: 100%;
}
.fixed-table-container thead th {
height: 0;
padding: 0;
margin: 0;
border-left: 1px solid #dddddd;
}
.fixed-table-container thead th:focus {
outline: 0 solid transparent;
}
.fixed-table-container thead th:first-child {
border-left: none;
border-top-left-radius: 4px;
-webkit-border-top-left-radius: 4px;
-moz-border-radius-topleft: 4px;
}
.fixed-table-container thead th .th-inner,
.fixed-table-container tbody td .th-inner {
padding: 8px;
line-height: 24px;
vertical-align: top;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.fixed-table-container thead th .sortable {
cursor: pointer;
background-position: right;
background-repeat: no-repeat;
padding-right: 30px;
}
.fixed-table-container thead th .both {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC');
}
.fixed-table-container thead th .asc {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg==');
}
.fixed-table-container thead th .desc {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII= ');
}
.fixed-table-container th.detail {
width: 30px;
}
.fixed-table-container tbody td {
border-left: 1px solid #dddddd;
}
.fixed-table-container tbody tr:first-child td {
border-top: none;
}
.fixed-table-container tbody td:first-child {
border-left: none;
}
/* the same color with .active */
.fixed-table-container tbody .selected td {
background-color: #f5f5f5;
}
.fixed-table-container .bs-checkbox {
text-align: center;
}
.fixed-table-container .bs-checkbox .th-inner {
padding: 8px 0;
}
.fixed-table-container input[type="radio"],
.fixed-table-container input[type="checkbox"] {
margin: 0 auto !important;
}
.fixed-table-container .no-records-found {
text-align: center;
}
.fixed-table-pagination div.pagination,
.fixed-table-pagination .pagination-detail {
margin-top: 10px;
margin-bottom: 10px;
}
.fixed-table-pagination div.pagination .pagination {
margin: 0;
}
.fixed-table-pagination .pagination a {
padding: 6px 12px;
line-height: 1.428571429;
}
.fixed-table-pagination .pagination-info {
line-height: 34px;
margin-right: 5px;
}
.fixed-table-pagination .btn-group {
position: relative;
display: inline-block;
vertical-align: middle;
}
.fixed-table-pagination .dropup .dropdown-menu {
margin-bottom: 0;
}
.fixed-table-pagination .page-list {
display: inline-block;
}
.fixed-table-toolbar .columns-left {
margin-right: 5px;
}
.fixed-table-toolbar .columns-right {
margin-left: 5px;
}
.fixed-table-toolbar .columns label {
display: block;
padding: 3px 20px;
clear: both;
font-weight: normal;
line-height: 1.428571429;
}
.fixed-table-toolbar .bs-bars,
.fixed-table-toolbar .search,
.fixed-table-toolbar .columns {
position: relative;
margin-top: 10px;
margin-bottom: 10px;
line-height: 34px;
}
.fixed-table-pagination li.disabled a {
pointer-events: none;
cursor: default;
}
.fixed-table-loading {
display: none;
position: absolute;
top: 42px;
right: 0;
bottom: 0;
left: 0;
z-index: 99;
background-color: #fff;
text-align: center;
}
.fixed-table-body .card-view .title {
font-weight: bold;
display: inline-block;
min-width: 30%;
text-align: left !important;
}
/* support bootstrap 2 */
.fixed-table-body thead th .th-inner {
box-sizing: border-box;
}
.table th, .table td {
vertical-align: middle;
box-sizing: border-box;
}
.fixed-table-toolbar .dropdown-menu {
text-align: left;
max-height: 300px;
overflow: auto;
}
.fixed-table-toolbar .btn-group > .btn-group {
display: inline-block;
margin-left: -1px !important;
}
.fixed-table-toolbar .btn-group > .btn-group > .btn {
border-radius: 0;
}
.fixed-table-toolbar .btn-group > .btn-group:first-child > .btn {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.fixed-table-toolbar .btn-group > .btn-group:last-child > .btn {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.bootstrap-table .table > thead > tr > th {
vertical-align: bottom;
border-bottom: 1px solid #ddd;
}
/* support bootstrap 3 */
.bootstrap-table .table thead > tr > th {
padding: 0;
margin: 0;
}
.bootstrap-table .fixed-table-footer tbody > tr > td {
padding: 0 !important;
}
.bootstrap-table .fixed-table-footer .table {
border-bottom: none;
border-radius: 0;
padding: 0 !important;
}
.bootstrap-table .pull-right .dropdown-menu {
right: 0;
left: auto;
}
/* calculate scrollbar width */
p.fixed-table-scroll-inner {
width: 100%;
height: 200px;
}
div.fixed-table-scroll-outer {
top: 0;
left: 0;
visibility: hidden;
width: 200px;
height: 150px;
overflow: hidden;
}
/* for get correct heights */
.fixed-table-toolbar:after, .fixed-table-pagination:after {
content: "";
display: block;
clear: both;
}

File diff suppressed because one or more lines are too long

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