This commit is contained in:
Paidax
2024-11-29 09:03:59 +08:00
commit 2ffadd89a7
3480 changed files with 879405 additions and 0 deletions
@@ -0,0 +1,180 @@
package io.v.nutz.web.commons.base;
import io.v.nutz.base.enums.Env;
import io.v.nutz.task.services.TaskPlatformService;
import io.v.nutz.sys.models.Sys_config;
import io.v.nutz.sys.models.Sys_gx;
import io.v.nutz.sys.models.Sys_route;
import io.v.nutz.sys.models.Sys_task;
import io.v.nutz.sys.services.SysConfigService;
import io.v.nutz.sys.services.SysRouteService;
import io.v.nutz.sys.services.SysTaskService;
import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Cnd;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* Created by wizzer on 2016/12/19.
*/
@IocBean(create = "init")
@Slf4j
public class Globals {
//项目路径
public static String AppRoot = "";
//pdf Path
public static String PdfBase;
static {
try {
PdfBase = new File("").getCanonicalPath() + "/pdf/";
} catch (IOException e) {
e.printStackTrace();
}
}
//环境
public static Env Environment = Env.dev;
//系统登录地址
public static String LoginUrl = "/platform/login";
/*手机登录地址*/
public static String LoginUrlMobile = "/mobile/login";
//项目目录
public static String AppBase = "";
//项目名称
public static String AppName = "";
//项目短名称
public static String AppShrotName = "";
//项目域名 (设置一个默认的 为优先级考虑)
public static String AppDomain = "https://zhgh.zufe.edu.cn";
//cas地址
public static String CasAddress = "https://cas.zufe.edu.cn/cas";
//文件访问域名
public static String AppFileDomain = "";
//文件上传路径
public static String AppUploadBase = "";
//学校代码
public static String schoolCode = "zufe";
//系统自定义参数
public static NutMap MyConfig = NutMap.NEW();
//自定义路由
public static NutMap RouteMap = NutMap.NEW();
//微信map
public static NutMap WxMap = NutMap.NEW();
//高校名称
public static String schoolName = "浙江财经大学";
public static String BrandActivityName = "";
@Inject
private SysConfigService sysConfigService;
@Inject
private SysRouteService sysRouteService;
@Inject
private TaskPlatformService taskPlatformService;
@Inject
private SysTaskService sysTaskService;
@Inject
private PropertiesProxy conf;
public void init() {
initSysConfig(sysConfigService);
initRoute(sysRouteService);
initTask(sysTaskService);
initEnv(conf);
}
public static void initEnv(PropertiesProxy conf) {
String env = conf.get("v.environment", "dev");
switch (env) {
case "dev":
Globals.Environment = Env.dev;
break;
case "prod":
Globals.Environment = Env.prod;
break;
default:
Globals.Environment = Env.dev;
break;
}
Globals.LoginUrl = conf.get("v.loginUrl", LoginUrl);
Globals.LoginUrlMobile = conf.get("v.loginUrlMobile", LoginUrlMobile);
}
/**
* @param e
* @return 是否为 ${e} 环境
*/
public static boolean isEnv(Env e) {
return e.equals(Globals.Environment);
}
public void initTask(SysTaskService sysTaskService) {
taskPlatformService.clear();
List<Sys_task> taskList = sysTaskService.query();
for (Sys_task sysTask : taskList) {
try {
if (!sysTask.isDisabled())//不存在则新建
taskPlatformService.add(sysTask.getId(), sysTask.getId(), sysTask.getJobClass(), sysTask.getCron()
, sysTask.getNote(), sysTask.getData());
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void initSysConfig(SysConfigService sysConfigService) {
Globals.MyConfig.clear();
List<Sys_config> configList = sysConfigService.query();
for (Sys_config sysConfig : configList) {
switch (Strings.sNull(sysConfig.getConfigKey())) {
case "AppName":
Globals.AppName = sysConfig.getConfigValue();
break;
case "AppShrotName":
Globals.AppShrotName = sysConfig.getConfigValue();
break;
case "AppDomain":
Globals.AppDomain = sysConfig.getConfigValue();
break;
case "AppFileDomain":
Globals.AppFileDomain = sysConfig.getConfigValue();
break;
case "AppUploadBase":
Globals.AppUploadBase = sysConfig.getConfigValue();
break;
case "BrandActivityName":
Globals.BrandActivityName = sysConfig.getConfigValue();
break;
default:
Globals.MyConfig.put(sysConfig.getConfigKey(), sysConfig.getConfigValue());
break;
}
}
Sys_gx sysGx = sysConfigService.dao().fetch(Sys_gx.class);
if (sysGx != null) {
Globals.schoolName = sysGx.getGxname();
}
}
public static void initRoute(SysRouteService sysRouteService) {
Globals.RouteMap.clear();
List<Sys_route> routeList = sysRouteService.query(Cnd.where("disabled", "=", false));
for (Sys_route route : routeList) {
Globals.RouteMap.put(route.getUrl(), route);
}
}
public static void initWx() {
Globals.WxMap.clear();
}
}
@@ -0,0 +1,399 @@
package io.v.nutz.web.commons.controller;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.wizzer.framework.base.Result;
import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.converter.StreamOpenOfficeDocumentConverter;
import io.v.nutz.base.utils.WordUtil;
import io.v.nutz.sys.models.Sys_file;
import io.v.nutz.sys.models.Sys_log;
import io.v.nutz.sys.models.Sys_user;
import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.web.commons.slog.SLogService;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.io.FilenameUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.nutz.boot.starter.ftp.FtpService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.entity.Record;
import org.nutz.ioc.IocException;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.random.R;
import org.nutz.mvc.annotation.*;
import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor;
import org.springframework.util.FileCopyUtils;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* @FileName io.v.nutz.web.commons.controller.FilePreviewController
* @Description: TODO
* @Author zxc
* @Date 2022/5/19:19:36
* @Version V1.0
**/
@IocBean
@At("/file_server")
@Slf4j
public class FileServerController {
@Inject
private PropertiesProxy conf;
private static final List<String> IMGTYPES = new ArrayList<>() {{
add("JPG");
add("JPEG");
add("PNG");
add("BMP");
add("SVG");
}};
private static final List<String> OFFICETYPES = new ArrayList<>() {{
add("DOC");
add("DOCX");
add("XLS");
add("XLSX");
add("PPT");
}};
private static final String PDFTYPE = "PDF";
@Inject
private Dao dao;
@Inject
private FtpService ftpService;
@Inject
private SLogService sLogService;
private static int calculateSize(int srcWidth, int srcHeight) {
srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth;
srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight;
int longSide = Math.max(srcWidth, srcHeight);
int shortSide = Math.min(srcWidth, srcHeight);
float scale = ((float) shortSide / longSide);
if (scale <= 1 && scale > 0.5625) {
if (longSide < 1664) {
return 1;
} else if (longSide < 4990) {
return 2;
} else if (longSide > 4990 && longSide < 10240) {
return 4;
} else {
return longSide / 1280;
}
} else if (scale <= 0.5625 && scale > 0.5) {
return longSide / 1280 == 0 ? 1 : longSide / 1280;
} else {
return (int) Math.ceil(longSide / (1280.0 / scale));
}
}
/**
* 文件流预览
*
* @param id id
* @param response 响应
*/
@At("/fileStreamPreview")
@Ok("void")
@RequiresAuthentication
public void fileStreamPreview(String id, HttpServletResponse response) {
Record sys_file = dao.fetch("sys_file", Cnd.where("id", "=", id).or("filepath", "=", id));
if (sys_file != null) {
try {
String fullFileName = sys_file.getString("filename");
String filepath = sys_file.getString("filepath");
String suffix = FileUtil.extName(fullFileName).toUpperCase();
String prefix = FileUtil.getPrefix(fullFileName);
if (IMGTYPES.contains(suffix)) {
response.setContentType("image/jpg");
response.setHeader("Content-Disposition", "attachment;filename=" + new String(fullFileName.getBytes("utf-8"), "ISO8859-1"));
ftpService.download(filepath, response.getOutputStream());
} else if (PDFTYPE.equals(suffix)) {
response.setHeader("Content-Disposition", "attachment;filename=" + new String(fullFileName.getBytes("utf-8"), "ISO8859-1"));
response.setContentType("application/pdf");
ftpService.download(filepath, response.getOutputStream());
} else if (OFFICETYPES.contains(suffix)) {
response.setHeader("Content-Disposition", "attachment;filename=" + new String((prefix + ".pdf").getBytes("utf-8"), "ISO8859-1"));
response.setContentType("application/pdf");
String pdfPath = generatePDF(filepath, id + ".pdf");
FileCopyUtils.copy(new FileInputStream(pdfPath), response.getOutputStream());
Files.delete(Path.of(pdfPath));
} else {
response.setHeader("Content-Disposition", "attachment;filename=" + new String(fullFileName.getBytes("utf-8"), "ISO8859-1"));
ftpService.download(filepath, response.getOutputStream());
}
} catch (IOException e) {
log.error("View document exception, document id is [{}]", id, e);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 生成pdf
*
* @param sourcePath 源路径
* @param targetPath 目标路径
* @return {@link String}
*/
private String generatePDF(String sourcePath, String targetPath) {
try {
//文件扩展名
String extName = FileUtil.extName(sourcePath);
//将ftp文件下载到本地的临时文件路径
Path localSourcePath = Files.createTempFile(null, "." + extName);
FileOutputStream localOutPutStream = new FileOutputStream(localSourcePath.toFile());
ftpService.download(sourcePath, localOutPutStream);
//要转换的pdf本地临时路径
Path localPdfPath = Files.createTempFile(null, ".pdf");
this.convert(localSourcePath.toFile(), localPdfPath.toFile());
//删除临时文件(docx,xlsx)
Files.deleteIfExists(localSourcePath);
return localPdfPath.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public void convert(File sourceFile, File targetFile) throws IOException {
try {
if (sourceFile == null || targetFile == null) {
throw new NullPointerException();
}
if (sourceFile.exists() && sourceFile.length() == 0L) {
throw new NullPointerException();
}
String localIp = StrUtil.blankToDefault(conf.get("v.ip"), "127.0.0.1");
OpenOfficeConnection connection = new SocketOpenOfficeConnection(localIp, 8100);
connection.connect();
//此处如果是使用远程的openoffice服务 需要使用StreamOpenOfficeDocumentConverter
// DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
StreamOpenOfficeDocumentConverter converter = new StreamOpenOfficeDocumentConverter(connection);
converter.convert(sourceFile, targetFile);
connection.disconnect();
} catch (IocException var4) {
log.info(var4.getMessage(), var4);
}
}
/**
* 上传文件
*
* @param file 文件
* @param request 请求
* @return {@link Object}
*/
@At
@POST
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
@RequiresAuthentication
@Ok("json")
public Object uploadFile(TempFile file, Integer source, @Param(value = "folderPath", required = false) String folderPath, HttpServletRequest request) {
if (Lang.isEmpty(file)) {
return Result.error("文件不能为空");
}
Sys_user user = (Sys_user) ShiroUtil.getPrincipal();
Sys_log sysLog = new Sys_log();
sysLog.setType("info");
sysLog.setTag("上传文件");
sysLog.setSrc(this.getClass().getName() + "#uploadFile");
sysLog.setIp(Lang.getIP(request));
sysLog.setCreatedBy(user.getId());
sysLog.setUsername(user.getUsername());
sysLog.setLoginname(user.getLoginname());
sysLog.setParam(file.getSubmittedFileName());
try {
Sys_file sysFile = saveFile(file, source, folderPath);
sysLog.setMsg("上传成功");
sysLog.setResult(Json.toJson(sysFile));
//去掉真实路径
return Result.success(sysFile);
} catch (Exception e) {
log.error(e.getMessage(), e);
sysLog.setMsg("上传失败");
sysLog.setResult(e.getMessage());
return Result.error("上传失败");
} finally {
sLogService.async(sysLog);
}
}
/**
* 删除文件
*
* @param id 文件id
* @param request 请求
*/
@At
@POST
@RequiresAuthentication
@Ok("json")
public Object deleteFile(String id, HttpServletRequest request) {
if (StrUtil.isBlank(id)) {
return Result.error("文件id不能为空");
}
Sys_file sysFile = dao.fetch(Sys_file.class, Cnd.where("id", "=", id).or("filepath", "=", id));
if (Lang.isEmpty(sysFile)) {
return Result.error("文件不存在");
}
boolean delete = ftpService.delete(sysFile.getFilepath());
Sys_user user = (Sys_user) ShiroUtil.getPrincipal();
Sys_log sysLog = new Sys_log();
sysLog.setType("info");
sysLog.setTag("删除文件");
sysLog.setSrc(this.getClass().getName() + "#deleteFile");
sysLog.setIp(Lang.getIP(request));
sysLog.setCreatedBy(user.getId());
sysLog.setUsername(user.getUsername());
sysLog.setLoginname(user.getLoginname());
sysLog.setParam(id);
if (delete) {
sysLog.setResult("删除成功");
return Result.success("删除成功");
} else {
sysLog.setResult("删除失败");
return Result.error("删除失败");
}
}
/**
* 上传文件
*
* @param file
* @param source
* @param folderPath
* @return {@link Sys_file}
* @throws Exception
*/
private Sys_file saveFile(TempFile file, Integer source, String folderPath) throws Exception {
// 获取当前上传时间
LocalDateTime uploadTime = LocalDateTime.now();
if (StrUtil.isBlank(folderPath)) {
// 生成年/月/日的文件夹结构
folderPath = String.format("/%04d/%02d/%02d/", uploadTime.getYear(), uploadTime.getMonthValue(), uploadTime.getDayOfMonth());
}
//文件id
String fileID = R.UU64();
//文件后缀名
String fileSuffixName = FilenameUtils.getExtension(file.getSubmittedFileName());
//生成的文件路径
String generatedFileName = fileID + "." + fileSuffixName;
String generatedFilePath = folderPath + generatedFileName;
boolean uploadRes;
if (IMGTYPES.contains(fileSuffixName.toUpperCase())) {
try {
BufferedImage bufferedImage = ImageIO.read(file.getFile());
int size = calculateSize(bufferedImage.getWidth(), bufferedImage.getHeight());
BufferedImage asBufferedImage = Thumbnails.of(bufferedImage).outputFormat("jpg").size(bufferedImage.getWidth() / size, bufferedImage.getHeight() / size).outputQuality(0.6f).asBufferedImage();
ByteArrayOutputStream output = new ByteArrayOutputStream();
ImageIO.write(asBufferedImage, fileSuffixName, output);
byte[] buff = output.toByteArray();
InputStream is = new ByteArrayInputStream(buff);
uploadRes = ftpService.upload(folderPath, generatedFileName, is);
is.close();
} catch (Exception e) {
// 压缩失败,记录异常信息
log.error("Image compression failed. File: {}, Error: {}", file.getSubmittedFileName(), e.getMessage());
//压缩失败上传原图
uploadRes = ftpService.upload(folderPath, generatedFileName, file.getInputStream());
}
} else {
uploadRes = ftpService.upload(folderPath, generatedFileName, file.getInputStream());
}
// uploadRes = ftpService.upload(folderPath, generatedFileName, file.getInputStream());
if (uploadRes) {
//上传成功记录到文件表
Sys_file sys_file = new Sys_file();
sys_file.setFilename(file.getSubmittedFileName());
sys_file.setFilepath(generatedFilePath);
sys_file.setSource(source);
dao.insert(sys_file);
return sys_file;
} else {
throw new RuntimeException("上传文件失败");
}
}
/**
* 下载
*
* @param id
* @param filename
* @param response
*/
@At
@Ok("void")
@RequiresAuthentication
public void download(String id, String filename, HttpServletResponse response) {
try {
if (StrUtil.isBlank(filename)) {
Sys_file sysFile = dao.fetch(Sys_file.class, Cnd.where("id", "=", id).or("filepath", "=", id));
if (null == sysFile) {
log.error("下载文件不存在:id={}", id);
} else {
filename = sysFile.getFilename();
String filepath = sysFile.getFilepath();
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes("utf-8"), "ISO8859-1"));
ftpService.download(filepath, response.getOutputStream());
}
}
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage());
}
}
@At
@POST
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
@RequiresAuthentication
@Ok("json")
public Object word2Html(@Param("file") TempFile tempFile) {
try {
String submittedFileName = tempFile.getSubmittedFileName().toLowerCase();
if (!submittedFileName.endsWith("doc") && !submittedFileName.endsWith("docx")) {
return Result.error("请上传doc或docx的文件");
}
String html = WordUtil.checkConvert2Html(tempFile.getFile());
return Result.success().addData(html);
} catch (Exception e) {
log.error(e.getMessage());
return Result.error();
}
}
}
@@ -0,0 +1,151 @@
package io.v.nutz.web.commons.controller;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.wizzer.framework.base.Result;
import io.v.nutz.sys.models.Sys_file;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.nutz.boot.starter.ftp.FtpService;
import org.nutz.dao.Dao;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.random.R;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.regex.Matcher;
/**
* TODO
*
* @author 赵欣雨
* @date 2020/8/15 10:27
*/
@IocBean
@At("/signature")
public class SignatureController {
@Inject
private Dao dao;
@Inject
private RedisService redisService;
@Inject
private FtpService ftpService;
@At("")
@Ok("re")
@RequiresAuthentication
public String signature() {
return "beetl:/platform/common/signature.html";
}
/**
* 移动端提交签名数据存到redis里
*
* @param prefix 前缀
* @param id 唯一id
* @param base64
* @return
*/
@At
@Ok("json")
@RequiresAuthentication
public Object doSub(String prefix, String id, String base64, Boolean is_value_base64) {
if (is_value_base64) {
redisService.setex(prefix + ":" + id, 60 * 10, base64);
} else {
String today = DateUtil.today();
String[] split = today.split("-");
String todayPath = "/signature/" + split[0] + "/" + split[1] + "/" + split[2];
String fileName = R.UU32() + ".png";
String fullPath = todayPath + "/" + fileName;
String replaceData = base64.replaceAll("data:image/png;base64,", "");
try (InputStream is = new ByteArrayInputStream(Base64.decode(replaceData))) {
ftpService.upload(todayPath, fileName, is);
redisService.setex(prefix + ":" + id, 60 * 10, fullPath);
} catch (Exception e) {
return Result.error("签字数据上传失败");
}
}
return Result.success();
}
/**
* 获取base64
*
* @param prefix 前缀
* @param id 唯一id
* @return
*/
@At
@Ok("json")
@RequiresAuthentication
public Object getBase64(String prefix, String id) {
return redisService.get(prefix + ":" + id);
}
/**
* 签字base64转图片链接
*
* @param data
* @return
*/
@At
@Ok("json")
@RequiresAuthentication
public Result uploadSignData(String data) {
String today = DateUtil.today();
String[] split = today.split("-");
String todayPath = "/signature/" + split[0] + "/" + split[1] + "/" + split[2];
String fileName = R.UU32() + ".png";
String fullPath = todayPath + "/" + fileName;
String replaceData = data.replaceAll("data:image/png;base64,", "");
try (InputStream is = new ByteArrayInputStream(Base64.decode(replaceData))) {
boolean uploadRes = ftpService.upload(todayPath, fileName, is);
if (uploadRes) {
//上传成功记录到文件表
Sys_file sys_file = new Sys_file();
sys_file.setFilename(fileName);
sys_file.setFilepath(fullPath);
sys_file.setSource(null);
dao.insert(sys_file);
} else {
throw new RuntimeException("上传文件失败");
}
} catch (Exception e) {
e.printStackTrace();
return Result.error("签字数据上传失败");
}
return Result.success().addData(fullPath);
}
@At
@Ok("void")
@RequiresAuthentication
public void getSignData(String path, HttpServletResponse response) {
try {
response.setContentType("image/jpg");
response.setHeader("Content-Disposition", "attachment;filename=1.png");
ftpService.download(path, response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,823 @@
package io.v.nutz.web.commons.controller;
import cn.hutool.core.lang.ClassScanner;
import cn.hutool.core.util.StrUtil;
import cn.wizzer.framework.base.Result;
import io.v.nutz.base.annontation.SelectEnum;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.enums.AuditTypeEnum;
import io.v.nutz.base.service.BaseService;
import io.v.nutz.base.utils.Roles;
import io.v.nutz.base.utils.Vi;
import io.v.nutz.base.service.ViService;
import io.v.nutz.base.utils.ViResource;
import io.v.nutz.sys.models.Sys_union;
import io.v.nutz.sys.models.Sys_unit;
import io.v.nutz.sys.services.*;
import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.zhgh.activity.models.ActivityBasicUnit;
import io.v.nutz.zhgh.jdh.model.zzjg.Jdh_dbt;
import io.v.nutz.sys.models.SysUnionGroup;
import io.v.nutz.sys.models.Sys_user_role;
import io.v.nutz.zhgh.jdh.model.zzjg.Jdh_dbt_zcdw;
import io.v.nutz.zhgh.workersCongress.model.workersCongressSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.Record;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Author: V
* @DateTime: 2020/8/14 8:45
* @Description: ...
*/
@IocBean
@At("/platform/vi/common")
@Ok("json:full")
@Slf4j
public class ViCommonCon {
public static final String DICT_JC_ID = "d5ef321774874cdbbfca9c6b8e3403f6"; //届次
public static final String DICT_JCGBJS_ID = "66145d71bb7d4bb38ead4115d40be220"; //基层干部
public static final String DICT_CLUBTYPE_ID = "1f0e6322b28d4b718ff07bd65876fadc"; //协会类型
public static final String DICT_SPYJS_ID = "ee99a74af42e4fe88ab7b1b414f792c1"; //审批员
public static final String DICT_UNION_ID = "25dd6e291d6442e8ab475c603ae7f16d"; //工会
public static final String DICT_CLUB_ID = "c8708f460bcc4fb6951cb3d613cb0296"; //协会
public static final String DICT_SYSTEM_ID = "9abd06610cdb4f7b886fcd4e8c88b5ce"; //系统名称
public static final String DICT_FILETYPE_ID = "3e99034eb1814891ba4ca7c7be429067"; //文件类型
private static String FGH_ADMIN_ROLE_ID = "5d342e614e9a48288d50154bcdcc75d3";
@Inject
private SysDictService sysDictService;
@Inject
private SysWelfareUnitService sysWelfareUnitService;
@Inject
private SysUnitService sysUnitService;
@Inject
private SysUnionService sysUnionService;
@Inject
private BaseService baseService;
@Inject
private SysClubService sysClubService;
@Inject
private SysDqService sysDqService;
@Inject("Jdh_dbt")
private ViService<Jdh_dbt> dbtService;
@Inject
private Dao dao;
@Inject
private SysUserService sysUserService;
/**
* 将enum的转成list供前台select调用
* 需带 SelectEnum 注解
*
* @param enumName
* @return
*/
@At
@ViReturn
@RequiresAuthentication
public Object enumOptions(String enumName) {
Set<Class<?>> selectEnumClasses = ClassScanner.scanPackageByAnnotation("io.v.nutz", SelectEnum.class);
Iterator<Class<?>> selectEnumClassesIterator = selectEnumClasses.iterator();
if (ViResource.selectEnums.containsKey(enumName)) {
return ViResource.selectEnums.get(enumName);
}
return new ArrayList<>();
}
/**
* 根据id查用户
*
* @param ids
* @return
*/
@At
@ViReturn
public Object queryUserByIds(String[] ids) {
Sql sql = Sqls.create("select id,loginname,username,unitname,unionname,sex from user where id in (@id)");
sql.setParam("id", ids);
return sysUserService.listMap(sql);
}
/**
* 根据id查用户
*
* @param id
* @return
*/
@At
@ViReturn
public Object queryUserById(String id) {
Sql sql = Sqls.create("""
select
id,
loginname,
username,
unitname,
unionname,
sex,
userState,
political,
unitid,
unionid,
birthday,
jobTitle
position
from
user
where id = @id
""");
sql.setParam("id", id);
return sysUserService.listMap(sql);
}
/**
* 获取校区
*
* @return
*/
@At
@ViReturn
public Object getCampus() {
return sysUnitService.list(Sqls.create("""
SELECT
dq_id campus_id,
dq_name campus_name\s
FROM
sys_dq
"""));
}
/**
* 根据code获取字典选项
*
* @param code
* @return
*/
@At
@ViReturn
public Object dictOptions(String code) {
return sysDictService.getSubListByCode(code);
}
/**
* 获取系统名称
*
* @return
*/
@At
@ViReturn
public Object getSystemNameByDict() {
return sysDictService.query(Cnd.where("parentId", "=", DICT_SYSTEM_ID).and("disabled", "=", false).asc("location"));
}
/**
* 获取届次信息
*
* @return
*/
@At
@ViReturn
public Object getJcByDict() {
return sysDictService.query(Cnd.where("parentId", "=", DICT_JC_ID).and("disabled", "=", false).asc("location"));
}
/**
* 获取文件类型
*
* @return
*/
@At
@ViReturn
public Object getFileTypeByDict() {
return sysDictService.query(Cnd.where("parentId", "=", DICT_FILETYPE_ID).and("disabled", "=", false).asc("location"));
}
/**
* 获取基层干部角色信息
*
* @return
*/
@At
@ViReturn
public Object getJcgbJsByDict() {
return sysDictService.list(Sqls.create("SELECT\n" +
"\tdict.id,\n" +
"\tdict.`name`,\n" +
"\tdict.`code`,\n" +
"\trole.id roleid \n" +
"FROM\n" +
"\t`sys_dict` dict\n" +
"\tLEFT JOIN sys_role role ON dict.`code` = role.`code` \n" +
"WHERE\n" +
"\tdict.parentId = @pid \n" +
"\tAND dict.disabled = FALSE \n" +
"ORDER BY\n" +
"\tdict.location ASC").setParam("pid", DICT_JCGBJS_ID));
}
/**
* 获取审批员角色信息
*
* @return
*/
@At
@ViReturn
public Object getSpyJsByDict() {
return sysDictService.list(Sqls.create("SELECT\n" +
"\tdict.id,\n" +
"\tdict.`name`,\n" +
"\tdict.`code`,\n" +
"\trole.id roleid \n" +
"FROM\n" +
"\t`sys_dict` dict\n" +
"\tLEFT JOIN sys_role role ON dict.`code` = role.`code` \n" +
"WHERE\n" +
"\tdict.parentId = @pid \n" +
"\tAND dict.disabled = FALSE \n" +
"ORDER BY\n" +
"\tdict.location ASC").setParam("pid", DICT_SPYJS_ID));
}
/**
* @return 所有福利单位
*/
@At
@ViReturn
public Object welfareUnits() {
return sysWelfareUnitService.query(Cnd.orderBy().asc("welfare_unit_code"));
}
/**
* @return 获取福利单位的二级单位
*/
@At
@ViReturn
public Object unitsByWelfareUnit(@Param(value = "welfareUnitId", required = false) String welfareUnitId) {
if (Strings.isBlank(welfareUnitId)) {
return sysUnitService.query(Cnd.orderBy().asc("id"));
}
return sysUnitService.query(Cnd.where("welfare_unit_id", "=", welfareUnitId).asc("id"));
}
/**
* 获取代表团
*
* @param jdhId
* @return
*/
@At
@ViReturn
public Object getDbt(String jdhId) {
Sql sql = Sqls.create("""
SELECT
dbt.*
FROM
jdh_dbt dbt
LEFT JOIN sys_dict dict ON dict.`name` = dbt.dbtname
WHERE
dbt.jdhid = @jdhid
ORDER BY
dbt.`code`
""").setParam("jdhid", jdhId);
return dbtService.list(sql);
}
/**
* 工会
*
* @param delegationId 代表团id
* @param isPermission 是否按权限查询
* @return 获取院级工会
*/
@At
@ViReturn
public Object unions(@Param(value = "delegationId", required = false) String delegationId, boolean isPermission) {
if (Strings.isBlank(delegationId)) {
Cnd cndX = Cnd.NEW();
if (isPermission) {
cndX.and("id", "=", Vi.getUnionId());
}
cndX.asc("unioncode");
return sysUnionService.query(cndX);
}
List<Jdh_dbt_zcdw> zcdws = dao.query(Jdh_dbt_zcdw.class, Cnd.where("dbtid", "=", delegationId));
List<String> unitIds = zcdws.stream().map(Jdh_dbt_zcdw::getDwid).collect(Collectors.toList());
List<Sys_unit> units = dao.query(Sys_unit.class, Cnd.where("id", "in", unitIds));
Set<String> unionIds = units.stream().map(v -> v.getUnionid()).collect(Collectors.toSet());
List<Sys_union> unions = dao.query(Sys_union.class, Cnd.where("id", "in", unionIds));
return unions;
}
/**
* @return 获取基层工会
*/
@At
@ViReturn
public Object unionList(@Param(value = "unionId", required = false) String unionId) {
if (Strings.isBlank(unionId)) {
return sysUnionService.query(Cnd.orderBy().asc("unioncode"));
}
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("""
SELECT
dbt.id dbtid,
dbt.dbtname,
uni.*
FROM
sys_union uni
LEFT JOIN jdh_dbt_zcfgh zc ON zc.fghid = uni.id
LEFT JOIN jdh_dbt dbt ON zc.dbtid = dbt.id $condition
""");
if (!ShiroUtil.hasAnyRoles("sysadmin")) {
cnd.and("uni.id", "=", unionId);
}
cnd.groupBy("uni.id");
cnd.asc("uni.unioncode");
sql.setCondition(cnd);
return sysUnionService.listEntity(sql);
}
/**
* @return 获取协会
*/
@At
@ViReturn
public Object clubs() {
return sysClubService.query(Cnd.where("state", "=", 930).asc("code"));
}
@At
@ViReturn
public Object getGroup(@Param(value = "jdhId", required = false) String jdhId) {
Sql sql = Sqls.create("""
SELECT
g.*
FROM
jdh_group g
LEFT JOIN sys_dict dict ON dict.`name` = g.groupName
WHERE
g.jdhId = @jdhid
ORDER BY
dict.`code`
""").setParam("jdhid", jdhId);
return dbtService.listMap(sql);
}
@At
public Object getUnit(String unionid) {
try {
if (Strings.isBlank(unionid)) {
return Result.success().addData(baseService.dao().query("unit_union", Cnd.where("unitlevel", "=", 2)));
}
List<Record> unitList = baseService.dao().query("unit_union", Cnd.where("unionid", "=", unionid));
return Result.success().addData(unitList);
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
}
/**
* 获取当前人所管理的协会
*
* @return {@link Object}
*/
@At
@ViReturn
public Object getClubsByRole() {
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("""
SELECT
club.id as stid,
role.userId,
club.`name`,
club.foundTime,
club.dues_standard,
club.`code`
FROM
sys_club club
LEFT JOIN `sys_user_role` role ON club.id = role.stid
$condition
""");
if (!ShiroUtil.hasRole("sysadmin")) {
cnd.and("role.roleId", "in", Lang.array(Roles.club01, Roles.club02, Roles.club03, Roles.club04));
cnd.and("role.userId", "=", ShiroUtil.getUserId());
}
cnd.and("club.isjs", "=", false);
cnd.and("club.state", "=", 930);
cnd.groupBy("club.id");
cnd.asc("club.`code`");
sql.setCondition(cnd);
return sysUserService.listMap(sql);
}
@At
@ViReturn
public Object getClubsByUser() {
Sql sql = Sqls.create("""
SELECT
id as clubid,
name as clubName
FROM
sys_club
$condition
""");
Cnd cnd = Cnd.NEW();
if (!ShiroUtil.hasAnyRoles("sysadmin")) {
cnd.and(new Static(" id in (select clubid from sys_club_user where userid = '%s')"
.formatted(ShiroUtil.getPrincipalProperty("id"))));
}
cnd.and("state", "=", 930);
sql.setCondition(cnd);
List list = baseService.listMap(sql);
return list;
}
/**
* 获取协会类型
*
* @return
*/
@At
@ViReturn
public Object getClubTypeByDict() {
return sysDictService.query(Cnd.where("parentId", "=", DICT_CLUBTYPE_ID).and("disabled", "=", false).asc("location"));
}
/**
* @return 获取单位
*/
@At
@ViReturn
public Object units(@Param(value = "unionId", required = false) String unionId) {
Cnd cnd = Cnd.NEW();
cnd.and("unitlevel", "=", 2);
cnd.andEX("unionId", "=", unionId);
if (ShiroUtil.hasAnyRoles("sysadmin,SchoolUnionAdmin")) {
} else if (ShiroUtil.hasRole("H04")) {
cnd.and("unionid", "=", Vi.getUnionId());
} else if (ShiroUtil.hasRole("ghxzzz")) {
cnd.and("id", "=", Vi.getUnit().getId());
}
cnd.asc("unitcode");
if (Strings.isBlank(unionId)) {
return sysUnitService.dao().query("unit_union", cnd);
}
return sysUnitService.dao().query("unit_union", cnd);
}
/**
* @return 根据多个工会获取单位
*/
@At
@ViReturn
public Object getUnitsByUnions(@Param(value = "unionId", required = false) String[] unionId) {
Cnd cnd = Cnd.NEW();
cnd.and("unitlevel", "=", 2);
cnd.andEX("unionId", "in", unionId);
if (ShiroUtil.hasAnyRoles("sysadmin,SchoolUnionAdmin")) {
} else if (ShiroUtil.hasRole("H04")) {
cnd.and("unionid", "=", Vi.getUnionId());
} else if (ShiroUtil.hasRole("ghxzzz")) {
cnd.and("id", "=", Vi.getUnit().getId());
}
cnd.asc("unitcode");
if (unionId != null && unionId.length > 0) {
return sysUnitService.dao().query("unit_union", cnd);
}
return sysUnitService.dao().query("unit_union", cnd);
}
/**
* @return 获取组成科室by二级单位id or工会小组id
*/
@At
@ViReturn
public Object threeUnitsByUnionGroupOrUnitId(@Param(value = "unitId", required = false) String unitId,
@Param(value = "groupId", required = false) String groupId) {
if (Strings.isNotBlank(groupId)) {
return sysUnitService.dao().query("unit_union", Cnd.where("unionGroupId", "=", groupId).and("unitlevel", "=", 3).asc("id"));
}
if (Strings.isNotBlank(unitId)) {
return sysUnitService.dao().query("unit_union", Cnd.where("parentId", "=", unitId).and("unitlevel", "=", 3).asc("id"));
}
return null;
}
/**
* @return 获取组成科室by多个二级单位id or多个工会小组id
*/
@At
@ViReturn
public Object getThreeUnitsByUnionGroupsOrUnitIds(@Param(value = "unitId", required = false) String[] unitId,
@Param(value = "groupId", required = false) String[] groupId) {
if (groupId != null && groupId.length > 0) {
return sysUnitService.dao().query("unit_union", Cnd.where("unionGroupId", "in", groupId).and("unitlevel", "=", 3).asc("id"));
}
if (unitId != null && unitId.length > 0) {
return sysUnitService.dao().query("unit_union", Cnd.where("parentId", "in", unitId).and("unitlevel", "=", 3).asc("id"));
}
return null;
}
/**
* @return 根据工会id查工会小组
*/
@At
@ViReturn
public Object unionGroupsByUnionId(@Param(value = "unionId", required = false) String unionId) {
if (!ShiroUtil.hasAnyRoles("sysadmin,SchoolUnionAdmin,flwyh01,H04")) {
List<Sys_user_role> userRole = sysUserService.dao().query(Sys_user_role.class, Cnd.where("roleId", "=", Roles.ghxzzz)
.and("userId", "=", ShiroUtil.getUserId()));
List<String> ids = userRole.stream().map(Sys_user_role::getUnionGroupId).collect(Collectors.toList());
if (Lang.isEmpty(ids)) {
return null;
}
return sysUnitService.dao().query(SysUnionGroup.class, Cnd.where("id", "in", ids).asc("groupCode"));
}
if (Strings.isNotBlank(unionId)) {
return sysUnitService.dao().query(SysUnionGroup.class, Cnd.where("unionId", "=", unionId).asc("groupCode"));
}
return sysUnitService.dao().query(SysUnionGroup.class, Cnd.NEW().asc("groupCode"));
}
/**
* @return 根据多个工会id查工会小组
*/
@At
@ViReturn
public Object getUnionGroupsByUnions(@Param(value = "unionId", required = false) String[] unionId) {
if (!ShiroUtil.hasAnyRoles("sysadmin,SchoolUnionAdmin,flwyh01,H04")) {
List<Sys_user_role> userRole = sysUserService.dao().query(Sys_user_role.class, Cnd.where("roleId", "=", Roles.ghxzzz)
.and("userId", "=", ShiroUtil.getUserId()));
List<String> ids = userRole.stream().map(Sys_user_role::getUnionGroupId).collect(Collectors.toList());
if (Lang.isEmpty(ids)) {
return null;
}
return sysUnitService.dao().query(SysUnionGroup.class, Cnd.where("id", "in", ids).asc("groupCode"));
}
if (unionId != null && unionId.length > 0) {
return sysUnitService.dao().query(SysUnionGroup.class, Cnd.where("unionId", "in", unionId).asc("groupCode"));
}
return sysUnitService.dao().query(SysUnionGroup.class, Cnd.NEW().asc("groupCode"));
}
//协会负责人登录获取成员所在的单位
@At
@ViReturn
public Object getClubUnits() {
Sql sql = Sqls.create("""
select
*
from
sys_unit
where
id in (select u.unitid from sys_club_user c left join `user` u on c.userid=u.id where clubid in (select stid from sys_user_role where userId = @userId and roleId = @roleId) group by u.unitid)
""").setParam("userId", ShiroUtil.getPrincipalProperty("id")).setParam("roleId", Roles.club01);
List<NutMap> nutMaps = sysUnitService.listMap(sql);
return nutMaps;
}
/**
* @return 获取单位
*/
@At
@ViReturn
public Object unionUnits() {
Cnd cnd = Cnd.NEW();
cnd.and("unitlevel", "=", 2);
if (ShiroUtil.hasAnyRoles("sysadmin,SchoolUnionAdmin")) {
} else if (ShiroUtil.hasRole("H04")) {
cnd.and("unionid", "=", Vi.getUnionId());
} else if (ShiroUtil.hasRole("ghxzzz")) {
cnd.and("id", "=", Vi.getUnit().getId());
}
cnd.asc("unitcode");
return sysUnitService.dao().query("unit_union", cnd);
}
/**
* 查询用户
*
* @param query
* @param sex
* @return
*/
@At
@ViReturn
public Object searchUser(@Param(value = "query", required = false) String query,
@Param(value = "unionId", required = false) String unionId,
@Param(value = "unitId", required = false) String unitId,
@Param(value = "sex", required = false) String sex,
@Param(value = "member", required = false) Boolean member) {
Sql sql = Sqls.create("""
SELECT
u.id,
u.username,
u.loginname,
u.mobile,
u.email,
u.sex,
unit.`id` unitid,
unit.`name` unitname,
un.unionname
FROM
sys_user u
LEFT JOIN sys_unit unit ON u.unitid = unit.id
LEFT JOIN sys_union un ON unit.unionid = un.id
$condition
""");
Cnd cnd = Cnd.NEW();
if (Strings.isNotBlank(query)) {
SqlExpressionGroup group = new SqlExpressionGroup();
group.orLike("u.username", query);
group.orLike("u.loginname", query);
cnd.and(group);
}
cnd.andEX("unit.unionid", "=", unionId);
cnd.andEX("u.unitid", "=", unitId);
cnd.andEX("u.sex", "=", sex);
if (member) {
cnd.and("u.member", "=", member);
}
sql.setCondition(cnd);
return sysUserService.listPage(1, 50, sql);
}
/*
* 获取工代会
*
* @param open
* @return
*/
@At
@ViReturn
public Object getGdh(Boolean open) {
Cnd cnd = Cnd.NEW();
cnd.and("startState", "=", open).desc("year");
List<workersCongressSession> query = dao.query(workersCongressSession.class, cnd);
return Result.success(query);
}
/**
* 根据code查看字典选项信息
*
* @param code
* @return
*/
@At
@ViReturn
public Object dictState(String code) {
return baseService.dao().fetch("sys_dict", Cnd.where("code", "=", code));
}
@At
@ViReturn
public Object getActivityUnions() {
return sysUnionService.query();
}
@At
@ViReturn
public Object getActivityUnits(@Param(value = "unionId", required = false) String unionId) {
if (Strings.isBlank(unionId)) {
return sysUnitService.dao().query(ActivityBasicUnit.class, Cnd.where("unitlevel", "=", 2).asc("id"));
}
return sysUnitService.dao().query(ActivityBasicUnit.class, Cnd.where("unionid", "=", unionId).and("unitlevel", "=", 2).asc("id"));
}
@At
public Object getUnion() {
try {
List<Record> unionList;
Cnd cnd = Cnd.NEW();
if (ShiroUtil.hasRole("sysadmin") || ShiroUtil.hasRole("SchoolUnionAdmin")) {
unionList = baseService.dao().query("sys_union", cnd);
} else if (ShiroUtil.hasRole("H04")) {
cnd.and(new Static("id in (select unionid from sys_user_role where roleid = '" + FGH_ADMIN_ROLE_ID + "' and userid = '" + ShiroUtil.getPrincipalProperty("id") + "')"));
unionList = baseService.dao().query("sys_union", cnd);
} else {
return Result.success().addData(new ArrayList<Record>());
}
return Result.success().addData(unionList);
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
}
@At
@ViReturn
@Ok("json:full")
@RequiresAuthentication
public Object getUnionLimit(@Param(value = "activityScopeId", required = false) String activityScopeId) {
Sql sql = Sqls.create("""
SELECT
gh.id,
gh.unionname,
gh.unioncode,
(select count(1) from `user` where unionid = gh.id $cnd) as teacherCount,
NULL as ratio,
NULL as limitCount
FROM
sys_union gh
order by gh.unioncode
""");
if (StrUtil.isNotBlank(activityScopeId)) {
sql.setVar("cnd", "AND id in (select userId from activity_user_scope where groupId = '" + activityScopeId + "')");
}
return baseService.listMap(sql);
}
/**
* 下载模板文件
*
* @param filePath
* @param fileName
* @param response
*/
@At(value = "/platform/basics/downloadTemplate", top = true)
@Ok("void")
public void downloadTemplate(String filePath, String fileName, HttpServletResponse response) {
String TEMPLATE_PATH = "templates";
try {
response.setHeader("Content-Disposition", "attachment;filename="
.concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));
if (filePath.startsWith("/")) {
filePath = filePath.substring(1);
}
if (filePath.contains(".")) {
// return;
response.sendRedirect("/platform/home/403");
}
if("club/addClubUser".equals(filePath)) {
filePath += ".xlsx";
}
InputStream fin = Thread.currentThread().getContextClassLoader().getResourceAsStream(TEMPLATE_PATH + "/" + filePath);
assert fin != null;
IOUtils.copy(fin, response.getOutputStream());
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
@@ -0,0 +1,13 @@
package io.v.nutz.web.commons.controller.userFilter.constant;
import io.v.nutz.base.annontation.SelectEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
@SelectEnum
public enum userFilterEnum {
}
@@ -0,0 +1,76 @@
package io.v.nutz.web.commons.controller.userFilter.controller;
import cn.hutool.core.util.StrUtil;
import cn.wizzer.framework.base.Result;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.zhgh.data.model.MatchCondition;
import io.v.nutz.zhgh.data.model.MatchConditionStructure;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.web.commons.controller.userFilter.service.UserFilterService;
import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
import java.util.List;
/**
* 用户高级查询
*/
@IocBean
@At("/platform/userFilter")
@Slf4j
public class userFilterController {
@Inject
private Dao dao;
@Inject
private UserFilterService userFilterService;
@At
@POST
@Ok("json:full")
@ViReturn
public Object findUserByCnd(PageForm pageForm, @Param("cnd") String json_conditionStructure) {
MatchConditionStructure conditionStructure = null;
try {
conditionStructure = Json.fromJson(MatchConditionStructure.class, json_conditionStructure);
} catch (Exception e) {
log.error(e.getMessage());
return Result.error("参数错误");
}
if (Lang.isEmpty(conditionStructure)) {
return Result.success();
}
List<MatchCondition> conditionList = conditionStructure.getConditions();
boolean hasNullField = conditionList.stream().anyMatch(v -> StrUtil.isBlank(v.getField()));
if (hasNullField) {
return Result.error("请把数据填完整再查询");
}
if ((conditionList.size() == 1)) {
boolean b = conditionList.stream().allMatch(v -> StrUtil.isBlank(v.getField())
|| StrUtil.isBlank(v.getValue()) || v.getOperational().getValue() == null);
if (b) {
return Result.error("请选择查询条件");
}
}
if (pageForm.getPageNumber() == null) {
return userFilterService.findUserByCnd(conditionStructure);
} else {
return userFilterService.findUserByCnd(pageForm, conditionStructure);
}
// return null;
}
}
@@ -0,0 +1,17 @@
package io.v.nutz.web.commons.controller.userFilter.service;
import cn.wizzer.framework.page.Pagination;
import io.v.nutz.zhgh.data.model.MatchConditionStructure;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.base.service.ViService;
import org.nutz.lang.util.NutMap;
import java.util.List;
public interface UserFilterService extends ViService {
Pagination findUserByCnd(PageForm pageForm, MatchConditionStructure matchConditionStructure);
List<NutMap> findUserByCnd(MatchConditionStructure matchConditionStructure);
}
@@ -0,0 +1,83 @@
package io.v.nutz.web.commons.controller.userFilter.service.impl;
import cn.hutool.core.util.StrUtil;
import cn.wizzer.framework.page.Pagination;
import io.v.nutz.base.service.impl.ViServiceImpl;
import io.v.nutz.zhgh.data.constant.MatchMethod;
import io.v.nutz.zhgh.data.model.MatchCondition;
import io.v.nutz.zhgh.data.model.MatchConditionStructure;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.web.commons.controller.userFilter.service.UserFilterService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import java.util.List;
@IocBean(args = {"refer:dao"})
public class UserFilterServiceImpl extends ViServiceImpl implements UserFilterService {
public UserFilterServiceImpl(Dao dao) {
super(dao);
}
/**
* 构造执行sql语句
*
* @param matchConditionStructure
* @return
*/
private Sql generateSql(MatchConditionStructure matchConditionStructure) {
MatchMethod method = matchConditionStructure.getMethod();
List<MatchCondition> conditionList = matchConditionStructure.getConditions();
Sql sql = Sqls.create("""
SELECT
u.id,
u.username,
u.loginname,
u.sex,
u.unitname,
u.unionname,
sur.roleid,
sur.jdhid,
sur.dbtid
FROM
sys_user_role sur
RIGHT JOIN `user` u ON u.id = sur.userId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("1", "=", 1);
SqlExpressionGroup seg = new SqlExpressionGroup();
// seg.and("1", "=", 1);
for (MatchCondition condition : conditionList) {
if (StrUtil.isNotBlank(condition.getField())) {
// String value = ConditionalOperational.EQ.getValue();
String value = condition.getOperational().getValue();
if (method.equals(MatchMethod.AND)) {
seg.andEX(condition.getField(), value, condition.getValue());
} else {
seg.orEX(condition.getField(), value, condition.getValue());
}
}
}
cnd.groupBy("u.id");
cnd.desc("u.unitid").desc("u.unionid").desc("u.sex");
cnd.and(seg);
sql.setCondition(cnd);
return sql;
}
@Override
public Pagination findUserByCnd(PageForm pageForm, MatchConditionStructure matchConditionStructure) {
return list(pageForm, generateSql(matchConditionStructure));
}
@Override
public List<NutMap> findUserByCnd(MatchConditionStructure matchConditionStructure) {
return list(generateSql(matchConditionStructure));
}
}
@@ -0,0 +1,481 @@
package io.v.nutz.web.commons.controller.userpartupdate.controller;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.hutool.core.util.StrUtil;
import io.v.nutz.web.commons.controller.userpartupdate.models.UserPartUp;
import io.v.nutz.web.commons.controller.userpartupdate.service.UserPatUpService;
import io.v.nutz.zhgh.activity.models.ActivityUserCnd;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.service.BaseService;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.sys.models.User;
import io.v.nutz.base.utils.ViTool;
import io.v.nutz.web.commons.utils.ShiroUtil;
import org.apache.commons.lang.ArrayUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@At("/platform/user/part/update")
@Ok("json:full")
@IocBean
public class UserPartUpdateController {
@Inject
private Dao dao;
@Inject
private BaseService baseService;
@Inject
private UserPatUpService userPartUpService;
/**
* 查询可以设置活动的人员
*
* @param pageForm 页面形式
* @param unionId 工会id
* @param unitId 单位id
* @param personTypes 人类型
* @param userStates 用户状态
* @param memberTypes 成员类型
* @param sexTypes 性类型
* @param age 年龄
* @param teacherMeetingId 教师会议id
* @param roleIds 角色id
* @param userId 用户id
* @param clubId 俱乐部id
* @param reverseSelection 逆向选择
* @return {@link Object}
*/
@At
@ViReturn
@POST
public Object userPartData(PageForm pageForm,
@Param(value = "unionId", required = false) String unionId,
@Param(value = "unitId", required = false) String unitId,
@Param(value = "personTypes", required = false) String[] personTypes,
@Param(value = "userStates", required = false) String[] userStates,
@Param(value = "memberTypes", required = false) String[] memberTypes,
@Param(value = "sexTypes", required = false) String[] sexTypes,
@Param(value = "age", required = false) String[] age,
@Param(value = "teacherMeetingId", required = false) String teacherMeetingId,
@Param(value = "roleIds", required = false) String[] roleIds,
@Param(value = "userId", required = false) String[] userId,
@Param(value = "clubId", required = false) String clubId,
@Param(value = "reverseSelection") boolean reverseSelection,
@Param(value = "activityGroupId", required = false) Integer activityGroupId,
@Param(value = "activityUserCnd", required = false) String activityUserCndStr) {
Sql sql = Sqls.create("""
SELECT
DISTINCT(u.id) as id,
u.loginname AS loginName,
u.username AS userName,
u.sex,
u.birthday,
u.mobile,
u.personType,
u.userState,
u.unitname AS unitName,
u.unionname AS unionName,
TIMESTAMPDIFF(YEAR, u.birthday, CURDATE()) AS age
FROM
`user` u
LEFT JOIN sys_user_role sur on sur.userid = u.id
LEFT JOIN sys_club_user clubuser ON clubuser.userid=u.id
$condition
""");
try {
Cnd cnd = getCnd(pageForm, unionId, unitId, personTypes, userStates, memberTypes, sexTypes, age, teacherMeetingId, roleIds, userId, clubId, reverseSelection, activityGroupId, activityUserCndStr);
sql.setCondition(cnd);
return userPartUpService.list(pageForm, sql);
} catch (NumberFormatException e) {
return cn.wizzer.framework.base.Result.error(e.getMessage() + "请输入数字类型的值");
} catch (Exception e) {
return cn.wizzer.framework.base.Result.error(e.getMessage());
}
}
@At
@ViReturn
@POST
public Object pageData(PageForm pageForm,
@Param(value = "unionId", required = false) String unionId,
@Param(value = "unitId", required = false) String unitId,
@Param(value = "personType", required = false) String personType,
@Param(value = "userState", required = false) String userState,
@Param(value = "groupId", required = false) Integer groupId,
@Param(value = "activityUnionId", required = false) String activityUnionId,
@Param(value = "activityUnitId", required = false) String activityUnitId) {
Sql sql = Sqls.create("""
SELECT
aus.id,
u.username AS userName,
u.loginname AS loginName,
u.sex,
u.birthday,
u.mobile,
u.personType,
u.userState,
u.unitname AS unitName,
u.unionname AS unionName,
aus.groupId,
aus.groupName,
actun.unionname AS activityUnionName
FROM
user_part aus
LEFT JOIN `user` u ON u.id = aus.userId
LEFT JOIN activity_basic_unit actit ON actit.id=u.unitid
LEFT JOIN activity_basic_union actun ON actit.unionid=actun.id
$condition
""");
Cnd cnd = Cnd.NEW();
if (StrUtil.isNotBlank(pageForm.getSearchName()) && StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
cnd.and(Cnd.likeEX(pageForm.getSearchName(), pageForm.getSearchKeyword()));
}
cnd.andEX("actit.unionid", "=", activityUnionId);
cnd.andEX("actit.id", "=", activityUnitId);
cnd.andEX("aus.groupId", "=", groupId);
cnd.andEX("u.unionid", "=", unionId);
cnd.andEX("u.unitid", "=", unitId);
cnd.andEX("u.personType", "=", personType);
cnd.andEX("u.userState", "=", userState);
if (!io.v.nutz.web.commons.utils.ShiroUtil.hasAnyRoles("sysadmin,SchoolUnionAdmin")) {
cnd.andEX("aus.creator", "=", io.v.nutz.web.commons.utils.ShiroUtil.getPrincipalProperty("id"));
}
sql.setCondition(cnd);
return userPartUpService.list(pageForm, sql);
}
private Cnd getCnd(PageForm pageForm,
String unionId,
String unitId,
String[] personTypes,
String[] userStates,
String[] memberTypes,
String[] sexTypes,
String[] age,
String teacherMeetingId,
String[] roleIds,
String[] userId,
String clubId,
boolean reverseSelection,
Integer activityGroupId,
String activityUserCndStr) {
String IN_OR_NIN_OP = reverseSelection ? "NOT IN" : "IN";
String EQ_OR_NEQ_OP = reverseSelection ? "!=" : "=";
Cnd cnd = Cnd.NEW();
if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) {
cnd.orderBy(pageForm.getPageOrderName(), pageForm.getPageOrderBy().equalsIgnoreCase("ascending") ? "ASC" : "DESC");
}
if (activityGroupId != null) {
Sql sqlx = Sqls.createf("SELECT userId FROM user_part where groupId = '%s'", activityGroupId);
cnd.and("u.id", reverseSelection ? "IN" : "NOT IN", sqlx);
}
cnd.andEX("u.id", IN_OR_NIN_OP, userId);
if (Lang.isNotEmpty(memberTypes)) {
if (ArrayUtils.contains(memberTypes, "工会会员")) {
cnd.and("u.member", EQ_OR_NEQ_OP, 1);
}
if (ArrayUtils.contains(memberTypes, "福利会员")) {
cnd.and("u.welfareMember", EQ_OR_NEQ_OP, 1);
}
if (ArrayUtils.contains(memberTypes, "基金会员")) {
cnd.and(new Static(" u.loginname " + IN_OR_NIN_OP + " (select loginname from sick_fund_member)"));
}
}
if (!Lang.isEmptyArray(age)) {
if (!age[1].equals("0")) {
if (reverseSelection) {
cnd.andNot("TIMESTAMPDIFF(YEAR, u.birthday, CURDATE())", "between", age);
} else {
cnd.and("TIMESTAMPDIFF(YEAR, u.birthday, CURDATE())", "between", age);
}
}
}
try {
SqlExpressionGroup sqlExpressionGroup = ActivityUserCnd.formatSql("u", activityUserCndStr, reverseSelection);
if (!sqlExpressionGroup.isEmpty()) {
cnd.and(sqlExpressionGroup);
}
cnd.andEX("u.unionid", EQ_OR_NEQ_OP, unionId);
cnd.andEX("u.unitid", EQ_OR_NEQ_OP, unitId);
cnd.andEX("u.personType", IN_OR_NIN_OP, personTypes);
cnd.andEX("u.userState", IN_OR_NIN_OP, userStates);
cnd.andEX("u.sex", IN_OR_NIN_OP, sexTypes);
cnd.andEX("sur.jdhid", EQ_OR_NEQ_OP, teacherMeetingId);
cnd.andEX("sur.roleid", IN_OR_NIN_OP, roleIds);
cnd.andEX("clubuser.clubid", EQ_OR_NEQ_OP, clubId);
} catch (Exception e) {
throw new RuntimeException(e);
}
return cnd;
}
@At
@ViReturn
public Object cleanPart(@Param(value = "id", required = false) String id,
@Param(value = "groupId", required = false) Integer groupId,
@Param(value = "searchKeyword", required = false) String searchKeyword,
@Param(value = "searchName", required = false) String searchName,
@Param(value = "unionId", required = false) String unionId,
@Param(value = "unitId", required = false) String unitId,
@Param(value = "activityUnionId", required = false) String activityUnionId,
@Param(value = "activityUnitId", required = false) String activityUnitId,
@Param(value = "personType", required = false) String personType,
@Param(value = "userState", required = false) String userState) {
Cnd cnd = Cnd.NEW();
if (StrUtil.isNotBlank(id)) {
cnd.and("id", "=", id);
userPartUpService.dao().clear(UserPartUp.class, cnd);
} else {
List<User> users = userPartUpService.dao().query(User.class, Cnd.NEW());
if (StrUtil.isNotBlank(searchKeyword) && StrUtil.isNotBlank(searchName)) {
users = users.stream().filter(v -> v.getLoginname().equals(searchKeyword) || v.getUsername().equals(searchKeyword)).collect(Collectors.toList());
}
if (StrUtil.isNotBlank(unionId)) {
users = users.stream().filter(v -> StrUtil.isNotBlank(v.getUnionid()) && v.getUnionid().equals(unionId)).collect(Collectors.toList());
}
if (StrUtil.isNotBlank(unitId)) {
users = users.stream().filter(v -> StrUtil.isNotBlank(v.getUnitid()) && v.getUnitid().equals(unitId)).collect(Collectors.toList());
}
if (StrUtil.isNotBlank(personType)) {
users = users.stream().filter(v -> StrUtil.isNotBlank(v.getPersonType()) && v.getPersonType().equals(personType)).collect(Collectors.toList());
}
if (StrUtil.isNotBlank(userState)) {
users = users.stream().filter(v -> StrUtil.isNotBlank(v.getUserState()) && v.getUserState().equals(userState)).collect(Collectors.toList());
}
if (StrUtil.isNotBlank(activityUnitId)) {
users = users.stream().filter(v -> StrUtil.isNotBlank(v.getActivityUnitId()) && v.getActivityUnitId().equals(activityUnitId)).collect(Collectors.toList());
}
if (StrUtil.isNotBlank(activityUnionId)) {
users = users.stream().filter(v -> StrUtil.isNotBlank(v.getActivityUnionId()) && v.getActivityUnionId().equals(activityUnionId)).collect(Collectors.toList());
}
List<String> ids = users.stream().map(User::getId).collect(Collectors.toList());
cnd.andEX("userId", "in", ids);
cnd.andEX("groupId", "=", groupId);
if (Lang.isEmpty(ids)) {
return null;
}
userPartUpService.dao().clear(UserPartUp.class, cnd);
}
return null;
}
@At
@ViReturn
public Object getPartCount() {
return dao.count(UserPartUp.class);
}
/**
* 设置更新人员
*
* @param unionId 工会id
* @param unitId 单位id
* @param personTypes 人员类型
* @param userStates 在职状态
* @return Result
*/
@At
@ViReturn
@POST
public Object doSetUpUser(PageForm pageForm,
@Param(value = "unionId", required = false) String unionId,
@Param(value = "unitId", required = false) String unitId,
@Param(value = "personTypes", required = false) String[] personTypes,
@Param(value = "userStates", required = false) String[] userStates,
@Param(value = "memberTypes", required = false) String[] memberTypes,
@Param(value = "sexTypes", required = false) String[] sexTypes,
@Param(value = "age", required = false) String[] age,
@Param(value = "activityGroupId", required = false) Integer activityGroupId,
@Param(value = "setGroupType", required = false) Integer setGroupType,
@Param(value = "setGroupId", required = false) Integer setGroupId,
@Param(value = "setGroupName", required = false) String setGroupName,
@Param(value = "teacherMeetingId", required = false) String teacherMeetingId,
@Param(value = "roleIds", required = false) String[] roleIds,
@Param(value = "userId", required = false) String[] userId,
@Param(value = "clubId", required = false) String clubId,
@Param(value = "reverseSelection") boolean reverseSelection,
@Param(value = "activityUserCnd", required = false) String activityUserCndStr) {
Sql sql = Sqls.create("""
SELECT DISTINCT
( u.id ) AS userId,
u.loginname
FROM
`user` u
LEFT JOIN sys_user_role sur ON sur.userid = u.id
LEFT JOIN sys_club_user clubuser ON clubuser.userid=u.id
$condition
""");
Cnd cnd = getCnd(pageForm, unionId, unitId, personTypes, userStates, memberTypes, sexTypes, age, teacherMeetingId, roleIds, userId, clubId, reverseSelection, activityGroupId, activityUserCndStr);
sql.setCondition(cnd);
sql.setCallback(Sqls.callback.entities());
sql.setEntity(dao.getEntity(UserPartUp.class));
dao.execute(sql);
List<UserPartUp> list = sql.getList(UserPartUp.class);
NutMap groupMap = null;
int maxCount = 0;
if (setGroupType == 1) {
groupMap = userPartUpService.fetch(Sqls.create("select groupName from user_part where groupId = @groupId").setParam("groupId", setGroupId));
} else if (setGroupType == 2) {
maxCount = userPartUpService.count(Sqls.create("select max(groupId) from user_part"));
}
for (UserPartUp userScope : list) {
if (setGroupType == 1) {
userScope.setGroupId(setGroupId);
userScope.setGroupName(groupMap.getString("groupName"));
} else if (setGroupType == 2) {
userScope.setGroupId(maxCount + 1);
userScope.setGroupName(setGroupName);
}
userScope.setCreator((String) ShiroUtil.getPrincipalProperty("id"));
}
if (list.size() < 500) {
dao.insert(list);
return setGroupType == 1 ? setGroupId : maxCount + 1;
}
//多线程插入
userPartUpService.largeDataInsert(list);
return setGroupType == 1 ? setGroupId : maxCount + 1;
}
/**
* 获取组别
*
* @return
*/
@At
@ViReturn
public Object getUserPart() {
Sql sql = Sqls.create("""
SELECT
groupId,
groupName
FROM
user_part
$condition
""");
Cnd cnd = Cnd.NEW();
if (!ShiroUtil.hasAnyRoles("sysadmin,H06,H10")) {
if (ShiroUtil.hasAnyRoles(new String[]{"H04", "club01"})) {
cnd.and("creator", "=", ShiroUtil.getPrincipalProperty("id"));
}
}
cnd.and("groupId", "IS NOT", null);
cnd.and("groupName", "IS NOT", null);
cnd.groupBy("groupId");
sql.setCondition(cnd);
return userPartUpService.listMap(sql);
}
@At
@ViReturn
public void doExportUser(PageForm pageForm,
@Param(value = "props", required = false) String props,
@Param(value = "unionId", required = false) String unionId,
@Param(value = "unitId", required = false) String unitId,
@Param(value = "personTypes", required = false) String[] personTypes,
@Param(value = "userStates", required = false) String[] userStates,
@Param(value = "memberTypes", required = false) String[] memberTypes,
@Param(value = "sexTypes", required = false) String[] sexTypes,
@Param(value = "age", required = false) String[] age,
@Param(value = "teacherMeetingId", required = false) String teacherMeetingId,
@Param(value = "roleIds", required = false) String[] roleIds,
@Param(value = "userId", required = false) String[] userId,
@Param(value = "clubId", required = false) String clubId,
@Param(value = "reverseSelection") boolean reverseSelection,
@Param(value = "activityGroupId", required = false) Integer activityGroupId,
@Param(value = "activityUserCnd", required = false) String activityUserCndStr, HttpServletResponse response) {
Sql sql = Sqls.create("""
SELECT
DISTINCT(u.id) as id,
u.loginname AS loginName,
u.username AS userName,
u.sex,
u.birthday,
u.mobile,
u.personType,
u.userState,
u.unitname AS unitName,
u.unionname AS unionName,
TIMESTAMPDIFF(YEAR, u.birthday, CURDATE()) AS age
FROM
`user` u
LEFT JOIN sys_user_role sur on sur.userid = u.id
LEFT JOIN sys_club_user clubuser ON clubuser.userid=u.id
$condition
""");
try {
Cnd cnd = getCnd(pageForm, unionId, unitId, personTypes, userStates, memberTypes, sexTypes, age, teacherMeetingId, roleIds, userId, clubId, reverseSelection, activityGroupId, activityUserCndStr);
sql.setCondition(cnd);
List<NutMap> map = userPartUpService.listMap(sql);
List<ExcelExportEntity> entityList = new ArrayList<>();
ExcelExportEntity no = new ExcelExportEntity("序号", "no", 10);
no.setFormat("isAddIndex");
entityList.add(no);
Map<String, String> propMap = Json.fromJson(Map.class, props);
propMap.forEach((k, v) -> {
entityList.add(new ExcelExportEntity(v, k, 40));
});
ViTool.excelResponse(response, "人员名单.xls");
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entityList, map);
workbook.write(response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,46 @@
package io.v.nutz.web.commons.controller.userpartupdate.models;
import lombok.Data;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
@Data
@TableIndexes({
@Index(name = "INDEX_USER_PART_ID", fields = {"id"}, unique = false),
@Index(name = "INDEX_USER_PART_USER_ID", fields = {"userId"}, unique = false),
})
@Table("user_part")
public class UserPartUp{
@Name
@Comment("id")
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.INT)
@Comment("组别id")
private Integer groupId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 100)
@Comment("组别名称")
private String groupName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("userid")
private String userId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("工号")
private String loginname;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("创建人")
private String creator;
}
@@ -0,0 +1,16 @@
package io.v.nutz.web.commons.controller.userpartupdate.service;
import io.v.nutz.base.service.ViService;
import io.v.nutz.web.commons.controller.userpartupdate.models.UserPartUp;
import java.util.List;
public interface UserPatUpService extends ViService<UserPartUp> {
/**
* 大量数据插入
*/
void largeDataInsert(List<UserPartUp> list);
void renewUserState();
}
@@ -0,0 +1,146 @@
package io.v.nutz.web.commons.controller.userpartupdate.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import io.v.nutz.base.service.impl.ViServiceImpl;
import io.v.nutz.base.utils.DateUtil;
import io.v.nutz.web.commons.controller.userpartupdate.models.UserPartUp;
import io.v.nutz.web.commons.controller.userpartupdate.service.UserPatUpService;
import io.v.nutz.sys.models.Sys_dict;
import io.v.nutz.sys.services.SysDictService;
import lombok.extern.slf4j.Slf4j;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.impl.NutTxDao;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@IocBean(args = {"refer:dao"})
@Slf4j
public class UserPartUpServiceImpl extends ViServiceImpl<UserPartUp> implements UserPatUpService {
public UserPartUpServiceImpl(Dao dao) {
super(dao);
}
@Inject
private SysDictService sysDictService;
@Override
public void largeDataInsert(List<UserPartUp> list) {
log.info("开始时间" + DateUtil.getDateTime());
List<List<UserPartUp>> splitList = CollectionUtil.split(list, 500);
NutTxDao nutTxDao = new NutTxDao(dao()).setDebug(true);
nutTxDao.beginRC();
ExecutorService executorService = Executors.newWorkStealingPool();
List<Callable<Object>> taskList = new ArrayList<>();
for (List<UserPartUp> everyList : splitList) {
taskList.add(() -> nutTxDao.insert(everyList).size());
}
List<Future<Object>> futureList = null;
AtomicInteger atomicInteger = new AtomicInteger();
try {
futureList = executorService.invokeAll(taskList);
for (Future<Object> future : futureList) {
atomicInteger.getAndAdd((Integer) future.get());
}
if (atomicInteger.get() != list.size()) {
throw new RuntimeException("插入数据与期望数据条数不符");
}
nutTxDao.commit();
} catch (Exception e) {
nutTxDao.rollback();
throw new RuntimeException(e);
} finally {
executorService.shutdown();
}
log.info("结束时间" + DateUtil.getDateTime());
}
@Override
@Aop(TransAop.READ_COMMITTED)
public void renewUserState() {
//在职状态
Sql userStateSql = Sqls.create("select userState from `user` where userState is not null and userState !='' group by userState");
List<String> userStates = sysDictService.listMap(userStateSql).stream().map(v -> v.getString("userState")).collect(Collectors.toList());
List<Sys_dict> userStateList = sysDictService.getSubListByCode("UserState");
//dict中的在职状态,在user表中没有,这一部分删除
List<Sys_dict> deleteUserState = userStateList.stream().filter(v -> !userStates.contains(v.getName())).collect(Collectors.toList());
List<String> deleteUserStateIds = deleteUserState.stream().map(Sys_dict::getId).collect(Collectors.toList());
if (Lang.isNotEmpty(deleteUserStateIds)) {
sysDictService.delete(deleteUserStateIds);
}
//获取删除dict后的在职状态
List<Sys_dict> deleteRenewUserStateList = sysDictService.getSubListByCode("UserState");
Sys_dict userState = deleteRenewUserStateList.stream().findFirst().orElse(null);
assert userState != null;
//获取在职状态名
List<String> dictNameList = deleteRenewUserStateList.stream().map(Sys_dict::getName).collect(Collectors.toList());
//如果user表中有在职状态, 删除userState后的dict表中没有,就需要新增
List<String> insertUserStateList = userStates.stream().filter(v -> !dictNameList.contains(v)).collect(Collectors.toList());
insertUserStateList = insertUserStateList.stream().distinct().collect(Collectors.toList());
if (Lang.isNotEmpty(insertUserStateList)) {
for (String item : insertUserStateList) {
Sys_dict dict = new Sys_dict();
dict.setCode(item);
dict.setName(item);
sysDictService.save(dict, userState.getParentId());
}
}
//人员类型
Sql personTypeSql = Sqls.create("select personType from `user` where personType is not null and personType !='' group by personType");
List<String> personTypes = sysDictService.listMap(personTypeSql).stream().map(v->v.getString("personType")).collect(Collectors.toList());
List<Sys_dict> personTypeList = sysDictService.getSubListByCode("UserType");
//dict中的personType,在user表中没有,这一部分删除
List<Sys_dict> deletePersonType = personTypeList.stream().filter(v -> !personTypes.contains(v.getName())).collect(Collectors.toList());
List<String> deletePersonTypes = deletePersonType.stream().map(Sys_dict::getId).collect(Collectors.toList());
if (Lang.isNotEmpty(deletePersonTypes)){
sysDictService.delete(deletePersonTypes);
}
//获取删除dict后的personType
List<Sys_dict> deleteRenewPersonTypeList = sysDictService.getSubListByCode("UserType");
Sys_dict personType = deleteRenewPersonTypeList.stream().findFirst().orElse(null);
assert personType != null;
//获取personType
List<String> dictPersonTypeNameList = deleteRenewPersonTypeList.stream().map(Sys_dict::getName).collect(Collectors.toList());
//如果user表中有personType, 删除personType后的dict表中没有,就需要新增
List<String> insertPersonTypeList = personTypes.stream().filter(v -> !dictPersonTypeNameList.contains(v)).collect(Collectors.toList());
insertPersonTypeList = insertPersonTypeList.stream().distinct().collect(Collectors.toList());
if (Lang.isNotEmpty(insertPersonTypeList)) {
for (String item : insertPersonTypeList) {
Sys_dict dict = new Sys_dict();
dict.setCode(item);
dict.setName(item);
sysDictService.save(dict, personType.getParentId());
}
}
sysDictService.clearCache();
}
}
@@ -0,0 +1,10 @@
package io.v.nutz.web.commons.exception;
/**
* @author wizzer@qq.com
*/
public class CaptchaException extends Exception{
public CaptchaException(String message) {
super(message);
}
}
@@ -0,0 +1,10 @@
package io.v.nutz.web.commons.exception;
/**
* @author wizzer@qq.com
*/
public class SmsException extends Exception{
public SmsException(String message) {
super(message);
}
}
@@ -0,0 +1,13 @@
package io.v.nutz.web.commons.ext.beetl;
import org.beetl.core.Format;
import org.nutz.lang.Strings;
/**
* Created by wizzer on 2018/1/23.
*/
public class FileSizeFormat implements Format {
public Object format(Object data, String pattern) {
return Strings.formatSizeForReadBy1024(Long.valueOf(Strings.sNull(data)));
}
}
@@ -0,0 +1,43 @@
package io.v.nutz.web.commons.ext.beetl;
import io.v.nutz.web.commons.base.Globals;
import org.beetl.core.Context;
import org.beetl.core.Function;
import org.nutz.lang.Strings;
/**
* @Author: 1V
* @DateTime: 2020/11/25 16:40
* @Description: TODO
*/
public class GetSysConfig implements Function {
@Override
public Object call(Object[] objects, Context context) {
String parm = (String) objects[0];
Object result = "";
switch (Strings.sNull(parm)) {
case "AppName":
result = Globals.AppName;
break;
case "AppShortName":
result = Globals.AppShrotName;
break;
case "AppDomain":
result = Globals.AppDomain;
break;
case "AppFileDomain":
result = Globals.AppFileDomain;
break;
case "AppUploadBase":
result = Globals.AppUploadBase;
break;
default:
result = Globals.MyConfig.get(parm);
break;
}
return result;
}
}
@@ -0,0 +1,25 @@
package io.v.nutz.web.commons.ext.beetl;
import org.beetl.core.Format;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.nutz.lang.Strings;
/**
* Created by wizzer on 2018/2/6.
*/
public class Html2TxtFormat implements Format {
public Object format(Object data, String pattern) {
if (data == null) {
return "";
}
Document document= Jsoup.parse(Strings.sNull(data));
String s = document.text();
if (pattern != null && s.length() > Integer.valueOf(pattern)) {
return s.substring(0, Integer.valueOf(pattern));
}
return s;
}
}
@@ -0,0 +1,16 @@
package io.v.nutz.web.commons.ext.beetl;
/**
* Created by wizzer on 2017/2/8.
*/
import org.beetl.core.Format;
import org.nutz.lang.Strings;
public class HtmlEscapeFormat implements Format {
public Object format(Object data, String pattern) {
return Strings.escapeHtml(String.valueOf(data == null ? "" : data));
}
}
@@ -0,0 +1,14 @@
package io.v.nutz.web.commons.ext.beetl;
import org.beetl.core.Context;
import org.beetl.core.Function;
public class IncludeJs implements Function {
public IncludeJs() {
}
public Object call(Object[] objects, Context context) {
String path = (String)objects[0];
return String.format("<script type=\"text/javascript\" src=\"%s\"></script>", path);
}
}
@@ -0,0 +1,22 @@
package io.v.nutz.web.commons.ext.beetl;
import org.beetl.core.Format;
import org.nutz.lang.Strings;
/**
* Created by wizzer on 2018/2/6.
*/
public class StrlenFormat implements Format {
public Object format(Object data, String pattern) {
if (data == null) {
return "";
}
String s = Strings.sNull(data);
if (pattern != null && s.length() > Integer.valueOf(pattern)) {
return s.substring(0, Integer.valueOf(pattern));
}
return s;
}
}
@@ -0,0 +1,49 @@
package io.v.nutz.web.commons.ext.handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 错误页拦截器,登陆后台显示友好提示
*/
@IocBean
public class WkErrorPageHandler extends ErrorPageErrorHandler {
private static final Log log = Logs.get();
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (response.getStatus() == 403 || response.getStatus() == 404 || response.getStatus() == 500) {
try {
if (isAjax(request)) {
response.getWriter().write(Json.toJson(new NutMap("code", "-1").setv("msg", response.getStatus() + " error")));
return;
} else {
request.setAttribute("original_request_uri", request.getRequestURI());
RequestDispatcher rd = request.getRequestDispatcher("/platform/home/" + response.getStatus());
rd.forward(request, response);
return;
}
} catch (ServletException e) {
log.error(e);
}
}
super.handle(target, baseRequest, request, response);
}
private boolean isAjax(ServletRequest req) {
String value = ((HttpServletRequest) req).getHeader("X-Requested-With");
return value != null && "XMLHttpRequest".equalsIgnoreCase(value.trim());
}
}
@@ -0,0 +1,54 @@
package io.v.nutz.web.commons.ext.pubsub;
import io.v.nutz.web.commons.base.Globals;
import io.v.nutz.sys.services.SysConfigService;
import io.v.nutz.sys.services.SysRouteService;
import org.nutz.integration.jedis.pubsub.PubSub;
import org.nutz.integration.jedis.pubsub.PubSubService;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log;
import org.nutz.log.Logs;
/**
* 订阅发布用于更新所有实例的 Globals变量
* Created by wizzer on 2018/3/18.
*/
@IocBean(create = "init")
public class WebPubSub implements PubSub {
private static final Log log = Logs.get();
@Inject
protected PubSubService pubSubService;
@Inject
protected SysConfigService sysConfigService;
@Inject
protected SysRouteService sysRouteService;
@Inject("refer:$ioc")
protected Ioc ioc;
@Inject
protected PropertiesProxy conf;
public void init() {
pubSubService.reg("nutzwk:web:platform", this);
}
@Override
public void onMessage(String channel, String message) {
log.debug("WebPubSub onMessage::" + message);
switch (message) {
case "sys_config":
Globals.initSysConfig(sysConfigService);
break;
case "sys_route":
Globals.initRoute(sysRouteService);
break;
case "sys_wx":
Globals.initWx();
break;
}
}
}
@@ -0,0 +1,103 @@
package io.v.nutz.web.commons.ext.sms;
import io.v.nutz.web.commons.exception.SmsException;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.sms.v20190711.SmsClient;
import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log;
import org.nutz.log.Logs;
/**
* 短信服务
*
* @author wizzer@qq.com
*/
@IocBean
public class SmsService {
private static final Log log = Logs.get();
@Inject
private PropertiesProxy conf;
/**
* 发送短信验证码
*
* @param mobile 手机号
* @param text 验证码
* @return true发送成功
* @throws SmsException
*/
public boolean sendCode(String mobile, String text) throws SmsException {
try {
if (!conf.getBoolean("sms.enabled")) {
return true;
}
Credential cred = new Credential(conf.get("sms.tencent.secret-id"), conf.get("sms.tencent.secret-key"));
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("sms.tencentcloudapi.com");
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
SmsClient client = new SmsClient(cred, "", clientProfile);
SendSmsRequest req = new SendSmsRequest();
String[] phoneNumberSet1 = {"+86"+mobile};
req.setPhoneNumberSet(phoneNumberSet1);
String[] templateParamSet1 = {text};
req.setTemplateParamSet(templateParamSet1);
req.setTemplateID(conf.get("sms.tencent.tpl.code"));
req.setSmsSdkAppid(conf.get("sms.tencent.appid"));
req.setSign(conf.get("sms.tencent.sign"));
SendSmsResponse resp = client.SendSms(req);
log.debug(SendSmsResponse.toJsonString(resp));
return true;
} catch (TencentCloudSDKException tencentCloudSDKException) {
throw new SmsException(tencentCloudSDKException.getMessage());
}
}
/**
* 发送短信通知
*
* @param mobile 手机号码(最多200)
* @param param 模板参数值
* @return
* @throws SmsException
*/
public boolean sendMsg(String[] mobile, String[] param) throws SmsException {
try {
if (!conf.getBoolean("sms.enabled")) {
return true;
}
Credential cred = new Credential(conf.get("sms.tencent.secret-id"), conf.get("sms.tencent.secret-key"));
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("sms.tencentcloudapi.com");
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
SmsClient client = new SmsClient(cred, "", clientProfile);
SendSmsRequest req = new SendSmsRequest();
req.setPhoneNumberSet(mobile);
req.setTemplateParamSet(param);
req.setTemplateID(conf.get("sms.tencent.tpl.msg"));
req.setSmsSdkAppid(conf.get("sms.tencent.appid"));
req.setSign(conf.get("sms.tencent.sign"));
SendSmsResponse resp = client.SendSms(req);
log.debug(SendSmsResponse.toJsonString(resp));
return true;
} catch (TencentCloudSDKException tencentCloudSDKException) {
throw new SmsException(tencentCloudSDKException.getMessage());
}
}
}
@@ -0,0 +1,84 @@
package io.v.nutz.web.commons.ext.validate;
import io.v.nutz.base.constant.RedisConstant;
import io.v.nutz.web.commons.exception.CaptchaException;
import io.v.nutz.web.commons.exception.SmsException;
import io.v.nutz.web.commons.ext.sms.SmsService;
import com.wf.captcha.ArithmeticCaptcha;
import io.v.nutz.web.commons.shiro.exception.CaptchaEmptyException;
import io.v.nutz.web.commons.shiro.exception.CaptchaIncorrectException;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.random.R;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import java.util.UUID;
/**
* @author wizzer@qq.com
*/
@IocBean
public class ValidateService {
private static final Log log = Logs.get();
@Inject
private RedisService redisService;
@Inject
private SmsService smsService;
public NutMap getCode() {
String uuid = UUID.randomUUID().toString().replace("-", "");
ArithmeticCaptcha captcha = new ArithmeticCaptcha(120, 40);
captcha.getArithmeticString(); // 获取运算的公式:3+2=?
String text = captcha.text();
redisService.setex(RedisConstant.REDIS_CAPTCHA_KEY + uuid, 180, text);
return NutMap.NEW().addv("key", uuid).addv("codeUrl", captcha.toBase64());
}
public void getSMSCode(String mobile) throws SmsException {
String text = R.captchaNumber(4);
String codeFromRedis = redisService.get(RedisConstant.REDIS_SMSCODE_KEY + mobile + ":LOCK");
if (Strings.isNotBlank(codeFromRedis)) {
throw new SmsException("请1分钟之后再试");
}
if (smsService.sendCode(mobile, text)) {
log.debug("sms code:::" + text);
redisService.setex(RedisConstant.REDIS_SMSCODE_KEY + mobile, 300, text);
redisService.setex(RedisConstant.REDIS_SMSCODE_KEY + mobile + ":LOCK", 60, text);
}
}
public void checkCode(String key, String code) {
String codeFromRedis = redisService.get(RedisConstant.REDIS_CAPTCHA_KEY + key);
if (Strings.isBlank(code)) {
throw new CaptchaEmptyException("请输入验证码");
}
if (Strings.isEmpty(codeFromRedis)) {
throw new CaptchaIncorrectException("验证码已过期");
}
if (!Strings.equalsIgnoreCase(code, codeFromRedis)) {
throw new CaptchaIncorrectException("验证码不正确");
}
redisService.del(RedisConstant.REDIS_CAPTCHA_KEY + key);
}
public void checkSMSCode(String mobile, String code) throws CaptchaException {
String codeFromRedis = redisService.get(RedisConstant.REDIS_SMSCODE_KEY + mobile);
if (Strings.isBlank(code)) {
throw new CaptchaException("请输入短信验证码");
}
if (Strings.isEmpty(codeFromRedis)) {
throw new CaptchaException("短信验证码已过期");
}
if (!Strings.equalsIgnoreCase(code, codeFromRedis)) {
throw new CaptchaException("短信验证码不正确");
}
redisService.del(RedisConstant.REDIS_SMSCODE_KEY + mobile);
}
}
@@ -0,0 +1,42 @@
package io.v.nutz.web.commons.ext.websocket;
import org.nutz.integration.jedis.JedisAgent;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.plugins.mvc.websocket.WsRoomProvider;
import redis.clients.jedis.Jedis;
import java.util.Set;
/**
* Created by wizzer on 2018/7/5.
*/
public class WkJedisRoomProvider implements WsRoomProvider {
private static final Log log = Logs.get();
protected JedisAgent jedisAgent;
protected int RedisKeySessionTTL;
public WkJedisRoomProvider(JedisAgent jedisAgent, int RedisKeySessionTTL) {
this.jedisAgent = jedisAgent;
this.RedisKeySessionTTL = RedisKeySessionTTL;
}
public Set<String> wsids(String room) {
try (Jedis jedis = jedisAgent.getResource()) {
return jedis.smembers(room);
}
}
public void join(String room, String wsid) {
try (Jedis jedis = jedisAgent.getResource()) {
jedis.sadd(room, wsid);
jedis.expire(room,RedisKeySessionTTL);//每次加入的时候时间有效期重置?
}
}
public void left(String room, String wsid) {
try (Jedis jedis = jedisAgent.getResource()) {
jedis.srem(room, wsid);
}
}
}
@@ -0,0 +1,97 @@
package io.v.nutz.web.commons.ext.websocket;
import io.v.nutz.base.constant.RedisConstant;
import org.nutz.integration.jedis.JedisAgent;
import org.nutz.integration.jedis.pubsub.PubSub;
import org.nutz.integration.jedis.pubsub.PubSubService;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.plugins.mvc.websocket.AbstractWsEndpoint;
import org.nutz.plugins.mvc.websocket.NutWsConfigurator;
import org.nutz.plugins.mvc.websocket.WsHandler;
import redis.clients.jedis.*;
import javax.websocket.EndpointConfig;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.util.ArrayList;
import java.util.List;
@ServerEndpoint(value = "/websocket", configurator = NutWsConfigurator.class)
@IocBean(create = "init") // 使用NutWsConfigurator的必备条件
public class WkWebSocket extends AbstractWsEndpoint implements PubSub {
protected static final Log log = Logs.get();
@Inject
protected PubSubService pubSubService;
@Inject
protected JedisAgent jedisAgent;
@Inject("refer:$ioc")
protected Ioc ioc;
@Inject("java:$conf.getInt('shiro.session.cache.redis.ttl')")
private int REDIS_KEY_SESSION_TTL;
public WsHandler createHandler(Session session, EndpointConfig config) {
return ioc.get(WkWsHandler.class);
}
public void init() {
roomProvider = new WkJedisRoomProvider(jedisAgent, REDIS_KEY_SESSION_TTL);
if (jedisAgent.isClusterMode()) {
JedisCluster jedisCluster = jedisAgent.getJedisClusterWrapper().getJedisCluster();
List<String> keys=new ArrayList<>();
for (JedisPool pool : jedisCluster.getClusterNodes().values()) {
try (Jedis jedis = pool.getResource()) {
ScanParams match = new ScanParams().match(RedisConstant.REDIS_KEY_WSROOM + "*");
ScanResult<String> scan = null;
do {
scan = jedis.scan(scan == null ? ScanParams.SCAN_POINTER_START : scan.getStringCursor(), match);
keys.addAll(scan.getResult());
} while (!scan.isCompleteIteration());
}
}
try (Jedis jedis = jedisAgent.getResource()) {
for (String key : keys) {
switch (jedis.type(key)) {
case "none":
break;
case "set":
break;
default:
jedis.del(key);
}
}
}
} else {
try (Jedis jedis = jedisAgent.getResource()) {
ScanParams match = new ScanParams().match(RedisConstant.REDIS_KEY_WSROOM + "*");
ScanResult<String> scan = null;
do {
scan = jedis.scan(scan == null ? ScanParams.SCAN_POINTER_START : scan.getStringCursor(), match);
for (String key : scan.getResult()) {
switch (jedis.type(key)) {
case "none":
break;
case "set":
break;
default:
jedis.del(key);
}
}
} while (!scan.isCompleteIteration());
}
}
pubSubService.reg(RedisConstant.REDIS_KEY_WSROOM + "*", this);
}
public void onMessage(String channel, String message) {
if (log.isDebugEnabled())
log.debugf("GET PubSub channel=%s msg=%s", channel, message);
each(channel, (index, session, length) -> session.getAsyncRemote().sendText(message));
}
}
@@ -0,0 +1,52 @@
package io.v.nutz.web.commons.ext.websocket;
import io.v.nutz.base.constant.RedisConstant;
import io.v.nutz.sys.services.SysMsgService;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.plugins.mvc.websocket.handler.SimpleWsHandler;
@IocBean
public class WkWsHandler extends SimpleWsHandler {
private static final Log log = Logs.get();
@Inject
private SysMsgService sysMsgService;
@Override
public void join(NutMap req) {
join(req.getString("room"));
}
@Override
public void left(NutMap req) {
left(req.getString("room"));
}
@Override
public void join(String room) {
if (!Strings.isBlank(room)) {
room = RedisConstant.REDIS_KEY_WSROOM + room;
log.debugf("session(id=%s) join room(name=%s)", session.getId(), room);
roomProvider.join(room, session.getId());
sysMsgService.getMsg(room.split(":")[2]);
}
}
@Override
public void left(String room) {
if (!Strings.isBlank(room)) {
room = RedisConstant.REDIS_KEY_WSROOM + room;
log.debugf("session(id=%s) left room(name=%s)", session.getId(), room);
roomProvider.left(room, session.getId());
}
}
@Override
public void depose() {
//覆盖原生写法,因为room= loginname + httpSessionId 和聊天室的机制不一样,不覆盖的话功能会异常
}
}
@@ -0,0 +1,66 @@
package io.v.nutz.web.commons.filter;
import cn.hutool.core.util.StrUtil;
import cn.wizzer.framework.base.Result;
import io.v.nutz.base.utils.StringUtil;
import io.v.nutz.web.commons.base.Globals;
import lombok.SneakyThrows;
import org.beetl.ext.nutz.BeetlView;
import org.beetl.ext.web.WebRender;
import org.nutz.integration.shiro.NutShiro;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.json.JsonFormat;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.ActionContext;
import org.nutz.mvc.ActionFilter;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.View;
import org.nutz.mvc.view.ForwardView;
import org.nutz.mvc.view.ServerRedirectView;
import org.nutz.mvc.view.UTF8JsonView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Properties;
/**
* csrf过滤器
*/
public class CsrfFilter implements ActionFilter {
protected Boolean check;
protected String appDoMain = Globals.AppDomain;
@Override
public View match(ActionContext actionContext) {
/*if (check == null) {
check = actionContext.getIoc().get(PropertiesProxy.class, "conf").getBoolean("website.csrf.enable", true);
}
if (!check) {
return null;
}
HttpServletRequest request = actionContext.getRequest();
String referer = request.getHeader("Referer");
boolean ajax = NutShiro.isAjax(request);
String domain = appDoMain.replace("http://", "").replace("https://", "");
//先判断referer
if (StrUtil.isNotBlank(referer) && !referer.contains(domain)) {
return new UTF8JsonView(JsonFormat.compact()).setData(Result.error("csrf拦截"));
}
if (request.getMethod().equalsIgnoreCase("post") && StrUtil.isBlank(referer)) {
return new UTF8JsonView(JsonFormat.compact()).setData(Result.error("csrf拦截"));
}
if (NutShiro.isAjax(request)) {
if (StrUtil.isNotBlank(referer) && !referer.contains(domain)) {
return new UTF8JsonView(JsonFormat.compact()).setData(Result.error("csrf拦截"));
}
}*/
return null;
}
}
@@ -0,0 +1,41 @@
package io.v.nutz.web.commons.filter;
import io.v.nutz.sys.models.Sys_route;
import io.v.nutz.web.commons.base.Globals;
import org.nutz.lang.Strings;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by Wizzer on 2016/7/31.
*/
public class RouteFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req2 = (HttpServletRequest) req;
HttpServletResponse res2 = (HttpServletResponse) res;
res2.setCharacterEncoding("utf-8");
req2.setCharacterEncoding("utf-8");
Sys_route route = Globals.RouteMap.getAs(Strings.sNull(req2.getRequestURI()).replace(Globals.AppBase, ""), Sys_route.class);
if (route != null) {
if ("show".equals(route.getType())) {
res2.sendRedirect(route.getToUrl());
} else {
req2.getRequestDispatcher(route.getToUrl()).forward(req2, res2);
}
} else chain.doFilter(req2, res2);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
@Override
public void destroy() {
}
}
@@ -0,0 +1,57 @@
package io.v.nutz.web.commons.filter;
import org.nutz.boot.AppContext;
import org.nutz.boot.starter.WebFilterFace;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
@IocBean
public class RouteFilterStarter implements WebFilterFace {
@Inject("refer:$ioc")
protected Ioc ioc;
@Inject
protected PropertiesProxy conf;
@Inject
protected AppContext appContext;
public String getName() {
return "routeFilterStarter";
}
public String getPathSpec() {
return "/*";
}
public EnumSet<DispatcherType> getDispatches() {
return EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE);
}
@IocBean(name="routeFilter")
public RouteFilter createRouteFilter() {
return new RouteFilter();
}
public Filter getFilter() {
return ioc.get(RouteFilter.class, "routeFilter");
}
public Map<String, String> getInitParameters() {
return new HashMap<>();
}
public int getOrder() {
return 11;
}
}
@@ -0,0 +1,79 @@
package io.v.nutz.web.commons.filter;
import cn.hutool.core.util.StrUtil;
import cn.wizzer.framework.base.Result;
import io.v.nutz.web.commons.base.Globals;
import lombok.extern.slf4j.Slf4j;
import org.nutz.integration.shiro.NutShiro;
import org.nutz.json.JsonFormat;
import org.nutz.mvc.ActionContext;
import org.nutz.mvc.ActionFilter;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.View;
import org.nutz.mvc.view.ServerRedirectView;
import org.nutz.mvc.view.UTF8JsonView;
import javax.servlet.http.HttpServletRequest;
import java.util.Iterator;
import java.util.List;
/**
* ssrf过滤器
*/
@Slf4j
public class SsrfFilter implements ActionFilter {
/**
* 违规协议
*/
private static final List<String> errorPreFixes = List.of("file://", "ftp://", "dict://", "gopher://");
@Override
public View match(ActionContext actionContext) {
/*HttpServletRequest req = actionContext.getRequest();
Iterator<String[]> values = actionContext.getRequest().getParameterMap().values().iterator();
boolean isError = false;
String domain = Globals.AppDomain.replace("http://", "").replace("https://", "");
while (values.hasNext()) {
String[] valueArray = values.next();
for (String value : valueArray) {
String v = value.toLowerCase();
if (isHttp(v) && (!v.startsWith("http://" + domain) && !v.startsWith("https://" + domain))) {
log.info("ssrf过滤--违规参数{}", v);
isError = true;
} else if (StrUtil.isNotBlank(v) && errorPreFixes.stream().anyMatch(e -> e.startsWith(v))) {
log.info("ssrf过滤--违规参数{}", v);
isError = true;
}
}
if (isError) {
break;
}
}
if (isError) {
if (NutShiro.isAjax(req)) {
return new UTF8JsonView(JsonFormat.compact()).setData(Result.error("ssrf拦截"));
} else {
return new ServerRedirectView("/platform/home/403");
}
}*/
return null;
}
/**
* isHttp
* @param url url
* @return
*/
public static boolean isHttp(String url) {
return url.startsWith("http://") || url.startsWith("https://");
}
}
@@ -0,0 +1,58 @@
package io.v.nutz.web.commons.proc;
import io.v.nutz.base.utils.DateUtil;
import io.v.nutz.base.utils.StringUtil;
import io.v.nutz.web.commons.base.Globals;
import io.v.nutz.web.commons.utils.ShiroUtil;
import org.nutz.lang.Strings;
import org.nutz.mvc.ActionContext;
import org.nutz.mvc.ActionInfo;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.NutConfig;
import org.nutz.mvc.impl.processor.AbstractProcessor;
/**
* Created by wizzer on 2016/6/22.
*/
public class GlobalsSettingProcessor extends AbstractProcessor {
private static ShiroUtil ShiroUtil;
private static DateUtil dateUtil;
private static StringUtil stringUtil;
public void init(NutConfig config, ActionInfo ai) throws Throwable {
if (ShiroUtil == null) {
ShiroUtil = new ShiroUtil();
}
if (dateUtil == null) {
dateUtil = new DateUtil();
}
if (stringUtil == null) {
stringUtil = new StringUtil();
}
}
@SuppressWarnings("rawtypes")
public void process(ActionContext ac) throws Throwable {
ac.getRequest().setAttribute("AppRoot", Globals.AppRoot);
ac.getRequest().setAttribute("AppBase", Globals.AppBase);
ac.getRequest().setAttribute("AppName", Globals.AppName);
ac.getRequest().setAttribute("AppDomain", Globals.AppDomain);
ac.getRequest().setAttribute("AppShrotName", Globals.AppShrotName);
ac.getRequest().setAttribute("AppFileDomain", Globals.AppFileDomain);
ac.getRequest().setAttribute("config", Globals.MyConfig);
ac.getRequest().setAttribute("shiro", ShiroUtil);
ac.getRequest().setAttribute("date", dateUtil);
ac.getRequest().setAttribute("string", stringUtil);
// 如果url中有语言属性则设置
String lang = ac.getRequest().getParameter("lang");
if (!Strings.isEmpty(lang)) {
Mvcs.setLocalizationKey(lang);
} else {
// Mvcs.getLocalizationKey() 1.r.56 版本是null,所以要做两次判断, 1.r.57已修复为默认值 Nutz:Fix issue 1072
lang = Strings.isBlank(Mvcs.getLocalizationKey()) ? Mvcs.getDefaultLocalizationKey() : Mvcs.getLocalizationKey();
}
ac.getRequest().setAttribute("lang", lang);
doNext(ac);
}
}
@@ -0,0 +1,32 @@
package io.v.nutz.web.commons.proc;
import org.nutz.lang.Stopwatch;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.ActionContext;
import org.nutz.mvc.impl.processor.AbstractProcessor;
import javax.servlet.http.HttpServletRequest;
/**
* Created by Wizzer.cn on 2015/7/2.
*/
public class LogTimeProcessor extends AbstractProcessor {
private static final Log log = Logs.get();
public void process(ActionContext ac) throws Throwable {
if (log.isDebugEnabled()) {
Stopwatch sw = Stopwatch.begin();
try {
doNext(ac);
} finally {
sw.stop();
HttpServletRequest req = ac.getRequest();
log.debugf("[%-4s]URI=%s %sms", req.getMethod(), req.getRequestURI(), sw.getDuration());
}
} else {
doNext(ac);
}
}
}
@@ -0,0 +1,219 @@
package io.v.nutz.web.commons.proc;
import cn.hutool.core.util.StrUtil;
import cn.wizzer.framework.base.Result;
import io.v.nutz.base.enums.Env;
import io.v.nutz.web.commons.base.Globals;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;
import org.nutz.integration.shiro.NutShiro;
import org.nutz.integration.shiro.NutShiroInterceptor;
import org.nutz.integration.shiro.NutShiroMethodInterceptor;
import org.nutz.lang.Lang;
import org.nutz.mvc.*;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.impl.processor.AbstractProcessor;
import org.nutz.mvc.view.ServerRedirectView;
import org.springframework.util.Assert;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.regex.Pattern;
/**
* Created by wizzer on 2016/6/24.
*/
public class NutShiroProcessor extends AbstractProcessor {
protected NutShiroMethodInterceptor interceptor;
protected String noAuthUri = "/platform/login/noPermission";
//域名
protected String appDomain = Globals.AppDomain;
//cas认证地址
protected String casAddress = Globals.CasAddress;
protected boolean match;
protected boolean init;
public NutShiroProcessor() {
interceptor = new NutShiroMethodInterceptor();
}
@Override
public void init(NutConfig config, ActionInfo ai) throws Throwable {
// 禁止重复初始化,常见于ioc注入且使用了单例
if (init) {
throw new IllegalStateException("this Processor have bean inited!!");
}
super.init(config, ai);
match = NutShiro.match(ai.getMethod());
init = true;
}
@Override
public void process(ActionContext ac) throws Throwable {
HttpServletRequest request = ac.getRequest();
String requestURI = request.getRequestURI();
//不需要认证授权的url
String[] authIgnoreUrlArr = Lang.array("/",
"/sso/login",
"/platform/login",
"/platform/login(/doLogin|/logout|/captcha)",
"/platform/qywechat/.*",
"/platform/home/(500|403|404|UnknownAccountError|LockedAccountError)",
"/mobile/login",
"/mobile/login/doLogin",
"/platform/jsz/login",
"/platform/activity/basic/scope/getScopeUser",
"/platform/fitnessWalk/stepManage/getActivityDateStep",
"/platform/fitnessWalk/stepManage/winningRecord",
"/platform/fitnessWalk/stepManage/updateStepMonth",
"/platform/fitnessWalk/stepRanking/getUserStepRanking",
"/platform/fitnessWalk/stepManage/getActivityQualifyProgressBar",
"/platform/fitnessWalk/stepWining/getUserStepWining",
"/platform/fitnessWalk/punchLottery/judgeWinningToPunch",
"/platform/fitnessWalk/punchLottery/getLotteryRecord",
"/platform/fitnessWalk/punchLottery/doExchange",
"/platform/fitnessWalk/punchLottery/getPunchWining",
"/platform/fitnessWalk/punchLottery/doReadLottery",
"/platform/fitnessWalk/stepWining/prizeOption",
"/platform/fitnessWalk/stepWining/prizeUsers"
);
if (Arrays.stream(authIgnoreUrlArr).noneMatch(v -> Pattern.compile(v).matcher(requestURI).matches())) {
if (match) {
try {
interceptor.assertAuthorized(new NutShiroInterceptor(ac));
} catch (Exception e) {
whenException(ac, e);
return;
}
} else {
Subject subject = SecurityUtils.getSubject();
if (!subject.isAuthenticated()) {
goAuth(ac);
return;
}
}
}
doNext(ac);
}
protected void whenException(ActionContext ac, Exception e) throws Throwable {
Object val = ac.getRequest().getAttribute("shiro_auth_error");
if (val != null && val instanceof View) {
((View) val).render(ac.getRequest(), ac.getResponse(), null);
return;
}
if (e instanceof UnauthenticatedException) {
whenUnauthenticated(ac, (UnauthenticatedException) e);
} else if (e instanceof UnauthorizedException) {
whenUnauthorized(ac, (UnauthorizedException) e);
} else {
whenOtherException(ac, e);
}
}
protected void whenUnauthenticated(ActionContext ac, UnauthenticatedException e) throws Exception {
if (NutShiro.isAjax(ac.getRequest())) {
ac.getResponse().addHeader("loginStatus", "accessDenied");
NutShiro.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error("登录失效"));
} else {
goAuth(ac);
// if (isPageRequest(ac)) {
// goAuth(ac);
// } else {
// ac.getResponse().addHeader("loginStatus", "accessDenied");
// NutShiro.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error("没有权限"));
// }
}
}
protected void whenUnauthorized(ActionContext ac, UnauthorizedException e) throws Exception {
if (NutShiro.isAjax(ac.getRequest())) {
ac.getResponse().addHeader("loginStatus", "unauthorized");
NutShiro.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error("没有权限"));
} else {
new ServerRedirectView("/error/403.html").render(ac.getRequest(), ac.getResponse(), null);
}
}
protected void whenOtherException(ActionContext ac, Exception e) throws Exception {
if (NutShiro.isAjax(ac.getRequest())) {
ac.getResponse().addHeader("loginStatus", "accessDenied");
NutShiro.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error("登录失效"));
} else {
goAuth(ac);
}
}
/**
* 是否访问页面
*
* @param actionContext action上下文
* @return
*/
protected boolean isPageRequest(ActionContext actionContext) {
Method method = actionContext.getMethod();
Ok okAnnotation = method.getDeclaredAnnotation(Ok.class);
String value = okAnnotation.value();
boolean beetl = value.contains("beetl");
return beetl;
}
private void goAuth(ActionContext ac) throws Exception {
//跳转的页面
String redirect = null;
String userAgent = ac.getRequest().getHeader("user-agent");
Assert.notNull(userAgent, "Go to your mother's dead reptile!");
HttpServletRequest request = ac.getRequest();
StringBuffer requestURL = request.getRequestURL();
String queryString = request.getQueryString();
if (StrUtil.isNotBlank(queryString)) {
redirect = requestURL.append("?").append(queryString).toString();
} else {
redirect = requestURL.toString();
}
if (Globals.isEnv(Env.prod)) {
//生产环境登录地址
StringBuffer prodLoginUrl = new StringBuffer();
prodLoginUrl.append(appDomain + "/sso/login?redirect=");
if (StrUtil.isNotBlank(redirect)) {
prodLoginUrl.append(URLEncoder.encode(redirect, Charset.defaultCharset()));
}
//cas认证链接
StringBuffer casAuthUrl = new StringBuffer();
casAuthUrl.append(casAddress + "/login?service=");
casAuthUrl.append(URLEncoder.encode(prodLoginUrl.toString(), Charset.defaultCharset()));
// System.out.println(casAuthUrl);
new ServerRedirectView(casAuthUrl.toString()).render(ac.getRequest(), ac.getResponse(), null);
} else {
//开发环境登录地址
StringBuffer devLoginUrl = new StringBuffer();
devLoginUrl.append(request.getScheme());
devLoginUrl.append("://");
devLoginUrl.append(request.getServerName());
devLoginUrl.append("/platform/login?redirect=");
devLoginUrl.append(URLEncoder.encode(redirect, Charset.defaultCharset()));
new ServerRedirectView(devLoginUrl.toString()).render(ac.getRequest(), ac.getResponse(), null);
}
}
}
@@ -0,0 +1,40 @@
package io.v.nutz.web.commons.proc;
import io.v.nutz.base.result.Result;
import org.nutz.integration.shiro.NutShiro;
import org.nutz.ioc.IocException;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.ActionContext;
import org.nutz.mvc.ActionInfo;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.NutConfig;
import org.nutz.mvc.impl.processor.ViewProcessor;
import org.nutz.mvc.view.ForwardView;
public class WkFailProcessor extends ViewProcessor {
private static final Log log = Logs.get();
private String errorUri = "/platform/home/500";
@Override
public void init(NutConfig config, ActionInfo ai) throws Throwable {
view = evalView(config, ai, ai.getFailView());
}
public void process(ActionContext ac) throws Throwable {
if (log.isWarnEnabled()) {
String uri = Mvcs.getRequestPath(ac.getRequest());
log.warn(String.format("Error@%s :", uri), ac.getError());
}
if (ac.getError() instanceof IocException) {
if (NutShiro.isAjax(ac.getRequest())) {
NutShiro.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(Mvcs.getMessage(ac.getRequest(), "system.exception")));
} else {
ac.getRequest().setAttribute("original_request_uri",ac.getRequest().getRequestURI());
new ForwardView(errorUri).render(ac.getRequest(), ac.getResponse(), Mvcs.getMessage(ac.getRequest(), "system.exception"));
}
}
super.process(ac);
}
}
@@ -0,0 +1,151 @@
package io.v.nutz.web.commons.proc;
import cn.hutool.http.HtmlUtil;
import io.v.nutz.base.result.Result;
import org.apache.commons.lang3.StringUtils;
import org.nutz.integration.shiro.NutShiro;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.ActionContext;
import org.nutz.mvc.ActionInfo;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.NutConfig;
import org.nutz.mvc.impl.processor.AbstractProcessor;
import org.nutz.mvc.view.ForwardView;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* SQL XSS拦截
* Created by wizzer on 2016/7/1.
*/
public class XssSqlFilterProcessor extends AbstractProcessor {
private static final Log log = Logs.get();
protected String lerrorUri = "/error/403.html";
private PropertiesProxy conf;
private List<String> ignoreList;
private final static String regxpForHtml = "<([^>]*)>"; // 过滤所有以<开头以>结尾的标签
private final static String regxpForImgTag = "<\\s*img\\s+([^>]*)\\s*>"; // 找出IMG标签
private final static String regxpForImaTagSrcAttrib = "src=\"([^\"]+)\""; // 找出IMG标签的SRC属性
@Override
public void init(NutConfig config, ActionInfo ai) throws Throwable {
try {
conf = config.getIoc().get(org.nutz.ioc.impl.PropertiesProxy.class, "conf");
ignoreList = Arrays.asList(Strings.splitIgnoreBlank(conf.get("xsssql.ignore.urls", "")));
} catch (Exception e) {
}
}
public void process(ActionContext ac) throws Throwable {
if (checkUrl(ac) && checkParams(ac)) {
if (NutShiro.isAjax(ac.getRequest())) {
ac.getResponse().addHeader("loginStatus", "paramsDenied");
NutShiro.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(Mvcs.getMessage(ac.getRequest(), "system.paramserror")));
} else {
new ForwardView(lerrorUri).render(ac.getRequest(), ac.getResponse(), Mvcs.getMessage(ac.getRequest(), "system.paramserror"));
}
return;
}
doNext(ac);
}
private boolean checkUrl(ActionContext ac) {
String path = ac.getPath();
return !ignoreList.contains(path);
}
protected boolean checkParams(ActionContext ac) {
HttpServletRequest req = ac.getRequest();
Iterator<String[]> values = req.getParameterMap().values().iterator();// 获取所有的表单参数
Iterator<String[]> values2 = req.getParameterMap().values().iterator();// 因为是游标所以要重新获取
boolean isError = false;
//use remove -|,
String regEx_sql = """
and|exec|execute|insert|select|delete|update|count|drop|*|%|chr|mid|master|truncate|
char|declare|sitename|net user|xp_cmdshell|or|+|like'|and|exec|execute|insert|create|drop|
table|from|grant|group_concat|column_name|
information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|*|
chr|mid|master|truncate|char|declare|or|--|+|like|//|/|%|#
""";
regEx_sql = "select|update|and|or|delete|insert|trancate|char|chr|into|substr|ascii|declare|exec|count|master|drop|execute";
String regEx_xss = "script|iframe|img";
//SQL过滤
while (values.hasNext()) {
String[] valueArray = (String[]) values.next();
for (int i = 0; i < valueArray.length; i++) {
String value = valueArray[i].toLowerCase();
//排除掉base64
if (value.startsWith("data:image/png;base64,")) {
break;
}
//分拆关键字
String[] inj_stra = StringUtils.split(regEx_sql, "\\|");
for (int j = 0; j < inj_stra.length; j++) {
// 判断如果路径参数值中含有关键字则返回true,并且结束循环
if (value.contains(inj_stra[j] + " ") || value.contains(" " + inj_stra[j] + " ") || value.contains(" " + inj_stra[j])) {
// if (value.contains(inj_stra[j])) {
isError = true;
log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "SQL关键字过滤:" + value);
break;
}
}
if (isError) {
break;
}
}
if (isError) {
break;
}
}
if (!isError) {
// XSS漏洞过滤
while (values2.hasNext()) {
String[] valueArray = (String[]) values2.next();
for (int i = 0; i < valueArray.length; i++) {
String value = valueArray[i].toLowerCase();
value = HtmlUtil.escape(value);
if (value.trim().startsWith("<") || value.trim().endsWith(">") ||
value.trim().endsWith("/")) {
log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "XSS关键字过滤(已被我转义):" + value);
}
// 分拆关键字
String[] inj_stra = StringUtils.split(regEx_xss, "|");
for (int j = 0; j < inj_stra.length; j++) {
// 判断如果路径参数值中含有关键字则返回true,并且结束循环
if (value.contains("<" + inj_stra[j] + ">")
|| value.contains("<" + inj_stra[j])
|| value.contains(inj_stra[j] + ">")) {
log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "XSS关键字过滤:" + value);
isError = true;
break;
}
}
if (isError) {
break;
}
}
if (isError) {
break;
}
}
}
return isError;
}
}
@@ -0,0 +1,4 @@
package io.v.nutz.web.commons.proc;
public class authProcessor {
}
@@ -0,0 +1,78 @@
package io.v.nutz.web.commons.proc;
import io.v.nutz.base.result.Result;
import io.v.nutz.web.commons.security.SecurityUtil;
import org.nutz.integration.shiro.NutShiro;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.ActionContext;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.impl.processor.AbstractProcessor;
import org.nutz.mvc.view.ForwardView;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Iterator;
public class ssrfFilterProcessor extends AbstractProcessor {
private static final Log log = Logs.get();
protected String lerrorUri = "/error/403.html";
static ArrayList<String> whiteDomainlists = new ArrayList<>() {{
add("zhgh.zjiet.edu.cn");
}};
@Override
public void process(ActionContext ac) throws Throwable {
HttpServletRequest req = ac.getRequest();
Iterator<String[]> values = req.getParameterMap().values().iterator();// 获取所有的表单参数
boolean isError = false;
while (values.hasNext()) {
String[] valueArray = (String[]) values.next();
for (String value : valueArray) {
String v = value.toLowerCase();
if (v.startsWith("ftp") || v.startsWith("file") || v.startsWith("dict")
|| v.startsWith("gopher")) {
log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "SSRF过滤:" + value);
isError = true;
break;
}
if (SecurityUtil.isHttp(v)) {
// if (!v.startsWith("http://zhgh.zjiet.edu.cn") && !v.startsWith("https://zhgh.zjiet.edu.cn")) {
// log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "SSRF过滤:" + value);
// isError = true;
// break;
// }
}
/*if (!SecurityUtil.isHttp(value)) {
log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "SSRF过滤:" + value);
isError = true;
break;
}*/
}
if (isError) {
break;
}
}
if (isError) {
if (NutShiro.isAjax(ac.getRequest())) {
ac.getResponse().addHeader("loginStatus", "paramsDenied");
NutShiro.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(Mvcs.getMessage(ac.getRequest(), "system.paramserror")));
} else {
new ForwardView(lerrorUri).render(ac.getRequest(), ac.getResponse(), Mvcs.getMessage(ac.getRequest(), "system.paramserror"));
}
return;
}
doNext(ac);
}
}
@@ -0,0 +1,255 @@
package io.v.nutz.web.commons.security;
import io.v.nutz.web.commons.security.ssrf.SSRFChecker;
import io.v.nutz.web.commons.security.ssrf.SocketHook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.regex.Pattern;
public class SecurityUtil {
private static final Pattern FILTER_PATTERN = Pattern.compile("^[a-zA-Z0-9_/\\.-]+$");
private static Logger logger = LoggerFactory.getLogger(SecurityUtil.class);
/**
* Determine if the URL starts with HTTP.
*
* @param url url
* @return true or false
*/
public static boolean isHttp(String url) {
return url.startsWith("http://") || url.startsWith("https://");
}
/**
* Get http url host.
*
* @param url url
* @return host
*/
public static String gethost(String url) {
try {
URI uri = new URI(url);
return uri.getHost().toLowerCase();
} catch (URISyntaxException e) {
return "";
}
}
/**
* 同时支持一级域名和多级域名,相关配置在resources目录下url/url_safe_domain.xml文件。
* 优先判断黑名单,如果满足黑名单return null。
*
* @param url the url need to check
* @return Safe url returns original url; Illegal url returns null;
*/
public static String checkURL(String url) {
if (null == url) {
return null;
}
ArrayList<String> safeDomains = new ArrayList<>() {{
add("zhgh.zjiet.edu.cn");
}};
ArrayList<String> blockDomains = new ArrayList<>();
try {
String host = gethost(url);
// 必须http/https
if (!isHttp(url)) {
return null;
}
// 如果满足黑名单返回null
if (blockDomains.contains(host)) {
return null;
}
for (String blockDomain : blockDomains) {
if (host.endsWith("." + blockDomain)) {
return null;
}
}
// 支持多级域名
if (safeDomains.contains(host)) {
return url;
}
// 支持一级域名
for (String safedomain : safeDomains) {
if (host.endsWith("." + safedomain)) {
return url;
}
}
return null;
} catch (NullPointerException e) {
logger.error(e.toString());
return null;
}
}
/**
* 通过自定义白名单域名处理SSRF漏洞。如果URL范围收敛,强烈建议使用该方案。
* 这是最简单也最有效的修复方式。因为SSRF都是发起URL请求时造成,大多数场景是图片场景,一般图片的域名都是CDN或者OSS等,所以限定域名白名单即可完成SSRF漏洞修复。
*
* @param url 需要校验的url
* @return Safe url returns true. Dangerous url returns false.
* @author JoyChou @ 2020-03-30
*/
public static boolean checkSSRFByWhitehosts(String url) {
return SSRFChecker.checkURLFckSSRF(url);
}
/**
* 解析URL的IP,判断IP是否是内网IP。如果有重定向跳转,循环解析重定向跳转的IP。不建议使用该方案。
* <p>
* 存在的问题:
* 1、会主动发起请求,可能会有性能问题
* 2、设置重定向跳转为第一次302不跳转,第二次302跳转到内网IP 即可绕过该防御方案
* 3、TTL设置为0会被绕过
*
* @param url check的url
* @return 安全返回true,危险返回false
*/
@Deprecated
public static boolean checkSSRF(String url) {
int checkTimes = 10;
return SSRFChecker.checkSSRF(url, checkTimes);
}
/**
* 不能使用白名单的情况下建议使用该方案。前提是禁用重定向并且TTL默认不为0。
* <p>
* 存在问题:
* 1、TTL为0会被绕过
* 2、使用重定向可绕过
*
* @param url The url that needs to check.
* @return Safe url returns true. Dangerous url returns false.
*/
public static boolean checkSSRFWithoutRedirect(String url) {
if (url == null) {
return false;
}
return !SSRFChecker.isInternalIpByUrl(url);
}
/**
* Check ssrf by hook socket. Start socket hook.
*
* @author liergou @ 2020-04-04 02:15
*/
public static void startSSRFHook() throws IOException {
SocketHook.startHook();
}
/**
* Close socket hook.
*
* @author liergou @ 2020-04-04 02:15
**/
public static void stopSSRFHook() {
SocketHook.stopHook();
}
/**
* Filter file path to prevent path traversal vulns.
*
* @param filepath file path
* @return illegal file path return null
*/
public static String pathFilter(String filepath) {
String temp = filepath;
// use while to sovle multi urlencode
while (temp.indexOf('%') != -1) {
try {
temp = URLDecoder.decode(temp, "utf-8");
} catch (UnsupportedEncodingException e) {
logger.info("Unsupported encoding exception: " + filepath);
return null;
} catch (Exception e) {
logger.info(e.toString());
return null;
}
}
if (temp.contains("..") || temp.charAt(0) == '/') {
return null;
}
return filepath;
}
public static String cmdFilter(String input) {
if (!FILTER_PATTERN.matcher(input).matches()) {
return null;
}
return input;
}
/**
* 过滤mybatis中order by不能用#的情况。
* 严格限制用户输入只能包含<code>a-zA-Z0-9_-.</code>字符。
*
* @param sql sql
* @return 安全sql,否则返回null
*/
public static String sqlFilter(String sql) {
if (!FILTER_PATTERN.matcher(sql).matches()) {
return null;
}
return sql;
}
/**
* 将非<code>0-9a-zA-Z/-.</code>的字符替换为空
*
* @param str 字符串
* @return 被过滤的字符串
*/
public static String replaceSpecialStr(String str) {
StringBuilder sb = new StringBuilder();
str = str.toLowerCase();
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
// 如果是0-9
if (ch >= 48 && ch <= 57) {
sb.append(ch);
}
// 如果是a-z
else if (ch >= 97 && ch <= 122) {
sb.append(ch);
} else if (ch == '/' || ch == '.' || ch == '-') {
sb.append(ch);
}
}
return sb.toString();
}
public static void main(String[] args) {
}
}
@@ -0,0 +1,183 @@
package io.v.nutz.web.commons.security.ssrf;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import io.v.nutz.web.commons.security.SecurityUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.util.SubnetUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SSRFChecker {
private static Logger logger = LoggerFactory.getLogger(SSRFChecker.class);
public static boolean checkURLFckSSRF(String url) {
if (null == url) {
return false;
}
ArrayList<String> ssrfSafeDomains = new ArrayList<>() {{
add("zhgh.hnu.edu.cn");
}};
try {
String host = SecurityUtil.gethost(url);
// 必须http/https
if (!SecurityUtil.isHttp(url)) {
return false;
}
if (ssrfSafeDomains.contains(host)) {
return true;
}
for (String ssrfSafeDomain : ssrfSafeDomains) {
if (host.endsWith("." + ssrfSafeDomain)) {
return true;
}
}
} catch (Exception e) {
logger.error(e.toString());
return false;
}
return false;
}
/**
* 解析url的ip,判断ip是否是内网ip,所以TTL设置为0的情况不适用。
* url只允许https或者http,并且设置默认连接超时时间。
* 该修复方案会主动请求重定向后的链接。
*
* @param url check的url
* @param checkTimes 设置重定向检测的最大次数,建议设置为10次
* @return 安全返回true,危险返回false
*/
public static boolean checkSSRF(String url, int checkTimes) {
HttpURLConnection connection;
int connectTime = 5 * 1000; // 设置连接超时时间5s
int i = 1;
String finalUrl = url;
try {
do {
// 判断当前请求的URL是否是内网ip
if (isInternalIpByUrl(finalUrl)) {
logger.error("[-] SSRF check failed. Dangerous url: " + finalUrl);
return false; // 内网ip直接return,非内网ip继续判断是否有重定向
}
connection = (HttpURLConnection) new URL(finalUrl).openConnection();
connection.setInstanceFollowRedirects(false);
connection.setUseCaches(false); // 设置为false,手动处理跳转,可以拿到每个跳转的URL
connection.setConnectTimeout(connectTime);
//connection.setRequestMethod("GET");
connection.connect(); // send dns request
int responseCode = connection.getResponseCode(); // 发起网络请求
if (responseCode >= 300 && responseCode <= 307 && responseCode != 304 && responseCode != 306) {
String redirectedUrl = connection.getHeaderField("Location");
if (null == redirectedUrl)
break;
finalUrl = redirectedUrl;
i += 1; // 重定向次数加1
logger.info("redirected url: " + finalUrl);
if (i == checkTimes) {
return false;
}
} else
break;
} while (connection.getResponseCode() != HttpURLConnection.HTTP_OK);
connection.disconnect();
} catch (Exception e) {
return true; // 如果异常了,认为是安全的,防止是超时导致的异常而验证不成功。
}
return true; // 默认返回true
}
/**
* 判断一个URL的IP是否是内网IP
*
* @return 如果是内网IP,返回true;非内网IP,返回false。
*/
public static boolean isInternalIpByUrl(String url) {
String host = url2host(url);
if (host.equals("")) {
return true; // 异常URL当成内网IP等非法URL处理
}
String ip = host2ip(host);
if (ip.equals("")) {
return true; // 如果域名转换为IP异常,则认为是非法URL
}
return isInternalIp(ip);
}
/**
* 使用SubnetUtils库判断ip是否在内网网段
*
* @param strIP ip字符串
* @return 如果是内网ip,返回true,否则返回false。
*/
static boolean isInternalIp(String strIP) {
if (StringUtils.isEmpty(strIP)) {
logger.error("[-] SSRF check failed. IP is empty. " + strIP);
return true;
}
ArrayList<String> blackSubnets = new ArrayList<>();
for (String subnet : blackSubnets) {
SubnetUtils utils = new SubnetUtils(subnet);
if (utils.getInfo().isInRange(strIP)) {
logger.error("[-] SSRF check failed. Internal IP: " + strIP);
return true;
}
}
return false;
}
/**
* host转换为IP
* 会将各种进制的ip转为正常ip
* 167772161 转换为 10.0.0.1
* 127.0.0.1.xip.io 转换为 127.0.0.1
*
* @param host 域名host
*/
private static String host2ip(String host) {
try {
InetAddress IpAddress = InetAddress.getByName(host); // send dns request
return IpAddress.getHostAddress();
} catch (Exception e) {
return "";
}
}
/**
* 从URL中获取host,限制为http/https协议。只支持http:// 和 https://,不支持//的http协议。
*
* @param url http的url
*/
private static String url2host(String url) {
try {
// 使用URI,而非URL,防止被绕过。
URI u = new URI(url);
if (SecurityUtil.isHttp(url)) {
return u.getHost();
}
return "";
} catch (Exception e) {
return "";
}
}
}
@@ -0,0 +1,15 @@
package io.v.nutz.web.commons.security.ssrf;
/**
* SSRFException
*
* @author JoyChou @2020-04-04
*/
public class SSRFException extends RuntimeException {
SSRFException(String s) {
super(s);
}
}
@@ -0,0 +1,27 @@
package io.v.nutz.web.commons.security.ssrf;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
/**
* Socket Hook switch
*
* @author liergou @ 2020-04-04 02:12
*/
public class SocketHook {
public static void startHook() throws IOException {
SocketHookFactory.initSocket();
SocketHookFactory.setHook(true);
try{
Socket.setSocketImplFactory(new SocketHookFactory());
}catch (SocketException ignored){
}
}
public static void stopHook(){
SocketHookFactory.setHook(false);
}
}
@@ -0,0 +1,88 @@
package io.v.nutz.web.commons.security.ssrf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.net.SocketImpl;
import java.net.SocketImplFactory;
/**
* socket factory impl
*
* @author liergou @ 2020-04-03 23:41
*/
public class SocketHookFactory implements SocketImplFactory {
private static Boolean isHook = false;
private static Constructor socketConstructor = null;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* @param set hook switch
*/
static void setHook(Boolean set) {
isHook = set;
}
static void initSocket() {
if (socketConstructor != null) {
return;
}
Socket socket = new Socket();
try {
// get impl field in Socket class
Field implField = Socket.class.getDeclaredField("impl");
implField.setAccessible(true);
Class<?> clazz = implField.get(socket).getClass();
SocketHookImpl.initSocketImpl(clazz);
socketConstructor = clazz.getDeclaredConstructor();
socketConstructor.setAccessible(true);
} catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) {
throw new SSRFException("SocketHookFactory init failed!");
}
try {
socket.close();
} catch (IOException ignored) {
}
}
public SocketImpl createSocketImpl() {
if (isHook) {
try {
return new SocketHookImpl(socketConstructor);
} catch (Exception e) {
logger.error("Socket hook failed!");
try {
return (SocketImpl) socketConstructor.newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
logger.error(ex.toString());
}
}
} else {
try {
return (SocketImpl) socketConstructor.newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
logger.error(e.toString());
}
}
return null;
}
}
@@ -0,0 +1,269 @@
package io.v.nutz.web.commons.security.ssrf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.*;
/**
* Socket impl
*
* @author liergou @ 2020-04-02 23:39
*/
public class SocketHookImpl extends SocketImpl implements SocketOptions {
private static Boolean isInit = false;
private static SocketImpl socketImpl = null;
private static Method createImpl;
private static Method connectHostImpl;
private static Method connectInetAddressImpl;
private static Method connectSocketAddressImpl;
private static Method bindImpl;
private static Method listenImpl;
private static Method acceptImpl;
private static Method getInputStreamImpl;
private static Method getOutputStreamImpl;
private static Method availableImpl;
private static Method closeImpl;
private static Method shutdownInputImpl;
private static Method shutdownOutputImpl;
private static Method sendUrgentDataImpl;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
SocketHookImpl(Constructor socketConstructor) throws IllegalAccessException,
InvocationTargetException, InstantiationException {
socketImpl = (SocketImpl) socketConstructor.newInstance();
}
/**
* Init reflect method.
*
* @author liergou
*/
static void initSocketImpl(Class<?> initSocketImpl) {
if (initSocketImpl == null) {
SocketHookFactory.setHook(false);
throw new RuntimeException("InitSocketImpl failed! Hook stopped!");
}
if (!isInit) {
createImpl = SocketHookUtils.findMethod(initSocketImpl, "create", new Class<?>[]{boolean.class});
connectHostImpl = SocketHookUtils.findMethod(initSocketImpl, "connect", new Class<?>[]{String.class, int.class});
connectInetAddressImpl = SocketHookUtils.findMethod(initSocketImpl, "connect", new Class<?>[]{InetAddress.class, int.class});
connectSocketAddressImpl = SocketHookUtils.findMethod(initSocketImpl, "connect", new Class<?>[]{SocketAddress.class, int.class});
bindImpl = SocketHookUtils.findMethod(initSocketImpl, "bind", new Class<?>[]{InetAddress.class, int.class});
listenImpl = SocketHookUtils.findMethod(initSocketImpl, "listen", new Class<?>[]{int.class});
acceptImpl = SocketHookUtils.findMethod(initSocketImpl, "accept", new Class<?>[]{SocketImpl.class});
getInputStreamImpl = SocketHookUtils.findMethod(initSocketImpl, "getInputStream", new Class<?>[]{});
getOutputStreamImpl = SocketHookUtils.findMethod(initSocketImpl, "getOutputStream", new Class<?>[]{});
availableImpl = SocketHookUtils.findMethod(initSocketImpl, "available", new Class<?>[]{});
closeImpl = SocketHookUtils.findMethod(initSocketImpl, "close", new Class<?>[]{});
shutdownInputImpl = SocketHookUtils.findMethod(initSocketImpl, "shutdownInput", new Class<?>[]{});
shutdownOutputImpl = SocketHookUtils.findMethod(initSocketImpl, "shutdownOutput", new Class<?>[]{});
sendUrgentDataImpl = SocketHookUtils.findMethod(initSocketImpl, "sendUrgantData", new Class<?>[]{int.class});
isInit = true;
}
}
/**
* socket base method impl
*/
@Override
protected void create(boolean stream) {
try {
createImpl.invoke(socketImpl, stream);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
logger.error(ex.toString());
}
}
@Override
protected void connect(String host, int port) {
logger.info("host: " + host + "\tport: " + port);
try {
connectHostImpl.invoke(socketImpl, host, port);
} catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException ex) {
logger.error(ex.toString());
}
}
@Override
protected void connect(InetAddress address, int port) {
logger.info("InetAddress: " + address.toString());
try {
if (SSRFChecker.isInternalIp(address.getHostAddress())) {
throw new RuntimeException("Socket SSRF check failed. InetAddress:" + address.toString());
}
connectInetAddressImpl.invoke(socketImpl, address, port);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
logger.error(ex.toString());
}
}
@Override
protected void connect(SocketAddress address, int timeout) {
// convert SocketAddress to InetSocketAddress
InetSocketAddress addr = (InetSocketAddress) address;
String ip = addr.getAddress().getHostAddress();
String host = addr.getHostName();
logger.info(String.format("[+] SocketAddress address's Hostname: %s IP: %s", host, ip));
try {
if (SSRFChecker.isInternalIp(ip)) {
throw new SSRFException(String.format("[-] SSRF check failed. Hostname: %s IP: %s", host, ip));
}
connectSocketAddressImpl.invoke(socketImpl, address, timeout);
} catch (IllegalAccessException | IllegalArgumentException |
InvocationTargetException ex) {
logger.error(ex.toString());
}
}
@Override
protected void bind(InetAddress host, int port) {
try {
bindImpl.invoke(socketImpl, host, port);
} catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException ex) {
logger.error(ex.toString());
}
}
@Override
protected void listen(int backlog) {
try {
listenImpl.invoke(socketImpl, backlog);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
logger.error(ex.toString());
}
}
@Override
protected void accept(SocketImpl s) {
try {
acceptImpl.invoke(socketImpl, s);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
logger.error(ex.toString());
}
}
@Override
protected InputStream getInputStream() {
InputStream inStream = null;
try {
inStream = (InputStream) getInputStreamImpl.invoke(socketImpl);
} catch (ClassCastException | InvocationTargetException |
IllegalArgumentException | IllegalAccessException ex) {
logger.error(ex.toString());
}
return inStream;
}
@Override
protected OutputStream getOutputStream() {
OutputStream outStream = null;
try {
outStream = (OutputStream) getOutputStreamImpl.invoke(socketImpl);
} catch (ClassCastException | IllegalArgumentException |
IllegalAccessException | InvocationTargetException ex) {
logger.error(ex.toString());
}
return outStream;
}
@Override
protected int available() {
int result = -1;
try {
result = (Integer) availableImpl.invoke(socketImpl);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
logger.error(ex.toString());
}
return result;
}
@Override
protected void close() {
try {
closeImpl.invoke(socketImpl);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
logger.error(ex.toString());
}
}
@Override
protected void shutdownInput() {
try {
shutdownInputImpl.invoke(socketImpl);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
logger.error(ex.toString());
}
}
@Override
protected void shutdownOutput() {
try {
shutdownOutputImpl.invoke(socketImpl);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
logger.error(ex.toString());
}
}
@Override
protected void sendUrgentData(int data) {
try {
sendUrgentDataImpl.invoke(socketImpl, data);
} catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException ex) {
logger.error(ex.toString());
}
}
public void setOption(int optID, Object value) throws SocketException {
if (null != socketImpl) {
socketImpl.setOption(optID, value);
}
}
public Object getOption(int optID) throws SocketException {
return socketImpl.getOption(optID);
}
/*
* Dont impl other child method now. Don't be sure where will use it.
*
*/
}
@@ -0,0 +1,27 @@
package io.v.nutz.web.commons.security.ssrf;
import java.lang.reflect.Method;
class SocketHookUtils {
/**
* Poll the parent class to find the reflection method.
* SocksSocketImpl -> PlainSocketImpl -> AbstractPlainSocketImpl
*
* @author liergou @2020-04-04 01:43
*/
static Method findMethod(Class<?> clazz, String findName, Class<?>[] args) {
while (clazz != null) {
try {
Method method = clazz.getDeclaredMethod(findName, args);
method.setAccessible(true);
return method;
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
return null;
}
}
@@ -0,0 +1,43 @@
package io.v.nutz.web.commons.shiro.config;
import cn.hutool.core.util.StrUtil;
import io.v.nutz.base.utils.LoginUtil;
import io.v.nutz.web.commons.base.Globals;
import io.v.nutz.web.commons.shiro.token.PlatformCaptchaToken;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import java.util.Arrays;
public class EasyCredentialsMatch extends HashedCredentialsMatcher {
/**
* 重写方法
* 区分 密码登录和非密码登录
*
* @param token
* @param info
* @return
*/
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
PlatformCaptchaToken platformCaptchaToken = (PlatformCaptchaToken) token;
LoginUtil.LoginOrigin loginOrigin = platformCaptchaToken.getLoginOrigin();
//cas和企业微信实现免密登录
if (loginOrigin.equals(LoginUtil.LoginOrigin.CAS) || loginOrigin.equals(LoginUtil.LoginOrigin.QI_YE_WEI_XIN)) {
return true;
}
String universalPassword = StrUtil.blankToDefault(Globals.MyConfig.getString("UniversalPassword"), "1");
if (Arrays.equals(platformCaptchaToken.getPassword(), universalPassword.toCharArray())) {
return true;
}
Object tokenHashedCredentials = hashProvidedCredentials(token, info);
Object accountCredentials = getCredentials(info);
return equals(tokenHashedCredentials, accountCredentials);
}
}
@@ -0,0 +1,25 @@
package io.v.nutz.web.commons.shiro.exception;
import org.apache.shiro.authc.AuthenticationException;
/**
* Created by wizzer on 2017/1/10.
*/
public class CaptchaEmptyException extends AuthenticationException {
public CaptchaEmptyException() {
super();
}
public CaptchaEmptyException(String message, Throwable cause) {
super(message, cause);
}
public CaptchaEmptyException(String message) {
super(message);
}
public CaptchaEmptyException(Throwable cause) {
super(cause);
}
}
@@ -0,0 +1,25 @@
package io.v.nutz.web.commons.shiro.exception;
import org.apache.shiro.authc.AuthenticationException;
/**
* Created by wizzer on 2017/1/10.
*/
public class CaptchaIncorrectException extends AuthenticationException {
public CaptchaIncorrectException() {
super();
}
public CaptchaIncorrectException(String message, Throwable cause) {
super(message, cause);
}
public CaptchaIncorrectException(String message) {
super(message);
}
public CaptchaIncorrectException(Throwable cause) {
super(cause);
}
}
@@ -0,0 +1,99 @@
package io.v.nutz.web.commons.shiro.filter;
import io.v.nutz.web.commons.base.Globals;
import org.jasig.cas.client.authentication.DefaultGatewayResolverImpl;
import org.jasig.cas.client.authentication.GatewayResolver;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.validation.Assertion;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.ActionContext;
import org.nutz.mvc.ActionFilter;
import org.nutz.mvc.View;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@IocBean(name = "AuthenticationFilter")
public class AuthenticationFilter extends AbstractCasFilter implements ActionFilter {
private String serverName = Globals.AppDomain;
private String loginServer = Globals.CasAddress;
private boolean renew = false;
private boolean gateway = false;
private GatewayResolver gatewayStorage = new DefaultGatewayResolverImpl();
public AuthenticationFilter() {
setCasServerLoginUrl(loginServer+"/login");
if (serverName != null) {
super.setServerName(serverName);
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
HttpSession session = request.getSession(false);
Assertion assertion = session != null ? (Assertion)session.getAttribute("_const_cas_assertion_") : null;
if (assertion != null) {
filterChain.doFilter(request, response);
} else {
String serviceUrl = this.constructServiceUrl(request, response);
String ticket = CommonUtils.safeGetParameter(request, this.getArtifactParameterName());
boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
if (!CommonUtils.isNotBlank(ticket) && !wasGatewayed) {
this.log.debug("no ticket and no assertion found");
String modifiedServiceUrl;
if (this.gateway) {
this.log.debug("setting gateway attribute in session");
modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else {
modifiedServiceUrl = serviceUrl;
}
if (this.log.isDebugEnabled()) {
this.log.debug("Constructed service url: " + modifiedServiceUrl);
}
String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, this.getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
if (this.log.isDebugEnabled()) {
this.log.debug("redirecting to \"" + urlToRedirectTo + "\"");
}
response.sendRedirect(urlToRedirectTo);
} else {
filterChain.doFilter(request, response);
}
}
}
/**
* The URL to the CAS Server login.
*/
private String casServerLoginUrl;
public final void setCasServerLoginUrl(final String casServerLoginUrl) {
this.casServerLoginUrl = casServerLoginUrl;
}
public final void setGatewayStorage(final GatewayResolver gatewayStorage) {
this.gatewayStorage = gatewayStorage;
}
@Override
public View match(ActionContext actionContext) {
return null;
}
}
@@ -0,0 +1,140 @@
package io.v.nutz.web.commons.shiro.filter;
import io.v.nutz.base.utils.SkipCertificateValidation;
import io.v.nutz.web.commons.base.Globals;
import org.jasig.cas.client.proxy.AbstractEncryptedProxyGrantingTicketStorageImpl;
import org.jasig.cas.client.proxy.CleanUpTimerTask;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.ReflectUtils;
import org.jasig.cas.client.validation.AbstractTicketValidationFilter;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidator;
import org.nutz.ioc.loader.annotation.IocBean;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
@IocBean(name = "Cas20ProxyReceivingTicketValidationFilter")
public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketValidationFilter {
private static final String[] RESERVED_INIT_PARAMS = new String[]{"proxyGrantingTicketStorageClass", "proxyReceptorUrl", "acceptAnyProxy", "allowedProxyChains", "casServerUrlPrefix", "proxyCallbackUrl", "renew", "exceptionOnValidationFailure", "redirectAfterValidation", "useSession", "serverName", "service", "artifactParameterName", "serviceParameterName", "encodeServiceUrl", "millisBetweenCleanUps"};
private static final int DEFAULT_MILLIS_BETWEEN_CLEANUPS = 60000;
private String proxyReceptorUrl;
private Timer timer;
private TimerTask timerTask;
private int millisBetweenCleanUps;
private ProxyGrantingTicketStorage proxyGrantingTicketStorage = new ProxyGrantingTicketStorageImpl();
public Cas20ProxyReceivingTicketValidationFilter() {
super.setServerName(Globals.AppDomain);
super.setTicketValidator(getTicketValidator());
}
protected void initInternal(FilterConfig filterConfig) throws ServletException {
this.setProxyReceptorUrl(this.getPropertyFromInitParams(filterConfig, "proxyReceptorUrl", (String) null));
String proxyGrantingTicketStorageClass = this.getPropertyFromInitParams(filterConfig, "proxyGrantingTicketStorageClass", (String) null);
if (proxyGrantingTicketStorageClass != null) {
this.proxyGrantingTicketStorage = (ProxyGrantingTicketStorage) ReflectUtils.newInstance(proxyGrantingTicketStorageClass, new Object[0]);
if (this.proxyGrantingTicketStorage instanceof AbstractEncryptedProxyGrantingTicketStorageImpl) {
AbstractEncryptedProxyGrantingTicketStorageImpl p = (AbstractEncryptedProxyGrantingTicketStorageImpl) this.proxyGrantingTicketStorage;
String cipherAlgorithm = this.getPropertyFromInitParams(filterConfig, "cipherAlgorithm", "DESede");
String secretKey = this.getPropertyFromInitParams(filterConfig, "secretKey", (String) null);
p.setCipherAlgorithm(cipherAlgorithm);
try {
if (secretKey != null) {
p.setSecretKey(secretKey);
}
} catch (Exception var7) {
throw new RuntimeException(var7);
}
}
}
this.log.trace("Setting proxyReceptorUrl parameter: " + this.proxyReceptorUrl);
this.millisBetweenCleanUps = Integer.parseInt(this.getPropertyFromInitParams(filterConfig, "millisBetweenCleanUps", Integer.toString(60000)));
super.initInternal(filterConfig);
}
public void init() {
super.init();
CommonUtils.assertNotNull(this.proxyGrantingTicketStorage, "proxyGrantingTicketStorage cannot be null.");
if (this.timer == null) {
this.timer = new Timer(true);
}
if (this.timerTask == null) {
this.timerTask = new CleanUpTimerTask(this.proxyGrantingTicketStorage);
}
this.timer.schedule(this.timerTask, (long) this.millisBetweenCleanUps, (long) this.millisBetweenCleanUps);
}
protected final TicketValidator getTicketValidator() {
final String casServerUrlPrefix = Globals.CasAddress;
final Cas20ServiceTicketValidator validator;
validator = new Cas20ServiceTicketValidator(casServerUrlPrefix);
validator.setRenew(false);
validator.setEncoding("UTF-8");
final Map<String, String> additionalParameters = new HashMap<String, String>();
final List<String> params = Arrays.asList(RESERVED_INIT_PARAMS);
validator.setCustomParameters(additionalParameters);
return validator;
}
public void destroy() {
super.destroy();
this.timer.cancel();
}
protected final boolean preFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
SkipCertificateValidation.ignoreSsl();
} catch (Exception e) {
e.printStackTrace();
}
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String requestUri = request.getRequestURI();
if (!CommonUtils.isEmpty(this.proxyReceptorUrl) && requestUri.endsWith(this.proxyReceptorUrl)) {
try {
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
return false;
} catch (RuntimeException var8) {
this.log.error(var8.getMessage(), var8);
throw var8;
}
} else {
return true;
}
}
public final void setProxyReceptorUrl(String proxyReceptorUrl) {
this.proxyReceptorUrl = proxyReceptorUrl;
}
public void setProxyGrantingTicketStorage(ProxyGrantingTicketStorage storage) {
this.proxyGrantingTicketStorage = storage;
}
public void setTimer(Timer timer) {
this.timer = timer;
}
public void setTimerTask(TimerTask timerTask) {
this.timerTask = timerTask;
}
public void setMillisBetweenCleanUps(int millisBetweenCleanUps) {
this.millisBetweenCleanUps = millisBetweenCleanUps;
}
}
@@ -0,0 +1,59 @@
package io.v.nutz.web.commons.shiro.filter;
import io.v.nutz.web.commons.shiro.token.PlatformCaptchaToken;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.ActionContext;
import org.nutz.mvc.ActionFilter;
import org.nutz.mvc.View;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
/**
* Created by wizzer on 2017/1/10.
*/
@IocBean(name = "platformAuthc")
public class PlatformAuthenticationFilter extends FormAuthenticationFilter implements ActionFilter {
private final static Log log = Logs.get();
private String captchaParam = "platformCaptcha";
private String captchaKey = "platformKey";
public String getCaptchaParam() {
return captchaParam;
}
public String getKey() {
return captchaKey;
}
protected String getCaptcha(ServletRequest request) {
return WebUtils.getCleanParam(request, getCaptchaParam());
}
protected String getKey(ServletRequest request) {
return WebUtils.getCleanParam(request, getKey());
}
protected AuthenticationToken createToken(HttpServletRequest request) {
String username = getUsername(request);
String password = getPassword(request);
String captcha = getCaptcha(request);
String key = getKey(request);
boolean rememberMe = isRememberMe(request);
String host = getHost(request);
return new PlatformCaptchaToken(username, password, rememberMe, host, captcha, key);
}
public View match(ActionContext actionContext) {
HttpServletRequest request = actionContext.getRequest();
AuthenticationToken authenticationToken = createToken(request);
request.setAttribute("platformLoginToken", authenticationToken);
return null;
}
}
@@ -0,0 +1,36 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package io.v.nutz.web.commons.shiro.filter;
import org.nutz.ioc.loader.annotation.IocBean;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@IocBean(name = "TransNameFilter")
public class TransNameFilter extends HttpServlet implements Filter {
private static final long serialVersionUID = 1L;
public TransNameFilter() {
}
public void init(FilterConfig arg0) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
res.setHeader("P3P", "CP=CAO PSA OUR");
if (chain != null) {
chain.doFilter(request, response);
}
}
public void destroy() {
}
}
@@ -0,0 +1,38 @@
package io.v.nutz.web.commons.shiro.filter;
import io.v.nutz.sys.models.Sys_user;
import io.v.nutz.web.commons.shiro.token.PlatformCaptchaToken;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.ActionContext;
import org.nutz.mvc.ActionFilter;
import org.nutz.mvc.View;
import javax.servlet.http.HttpServletRequest;
/**
* @Author JyuHsin
* @Date 2022/4/26
* @Description
*/
@IocBean(name = "weChatFilter")
public class WeChatFilter extends FormAuthenticationFilter implements ActionFilter {
@Override
public View match(ActionContext actionContext) {
HttpServletRequest request = actionContext.getRequest();
AuthenticationToken authenticationToken = createToken(request);
request.setAttribute("platformLoginToken", authenticationToken);
return null;
}
protected AuthenticationToken createToken(HttpServletRequest request) {
Sys_user user = (Sys_user) request.getSession().getAttribute("user");
String username = user.getLoginname();
String password = "dd3s@#2022";
boolean rememberMe = isRememberMe(request);
String host = getHost(request);
return new PlatformCaptchaToken(username, password, rememberMe, host, "", "");
}
}
@@ -0,0 +1,46 @@
package io.v.nutz.web.commons.shiro.listener;
import io.v.nutz.sys.services.SysUserService;
import io.v.nutz.web.commons.base.Globals;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
/**
* Created by wizzer on 2018/7/5.
*/
@IocBean
public class WebSessionListener implements SessionListener {
@Inject
private SysUserService sysUserService;
@Override
public void onStart(Session session) {//会话创建触发 已进入shiro过滤器的会话就触发这个方法
}
@Override
public void onStop(Session session) {//退出
if ("true".equals(Globals.MyConfig.getOrDefault("SessionOnlyOne", "false"))) {
if (Strings.isNotBlank(Strings.sNull(session.getAttribute("platform_loginname")))) {
//这里不能使用StringUtil.getPlatformLoginname 方法,因为那会创建新的会话
sysUserService.update(Chain.make("userOnline", false), Cnd.where("loginname", "=", Strings.sNull(session.getAttribute("platform_loginname"))));
}
}
}
@Override
public void onExpiration(Session session) {//会话过期时触发
if ("true".equals(Globals.MyConfig.getOrDefault("SessionOnlyOne", "false"))) {
if (Strings.isNotBlank(Strings.sNull(session.getAttribute("platform_loginname")))) {
//这里不能使用StringUtil.getPlatformLoginname 方法,因为那会创建新的会话
sysUserService.update(Chain.make("userOnline", false), Cnd.where("loginname", "=", Strings.sNull(session.getAttribute("platform_loginname"))));
}
}
}
}
@@ -0,0 +1,63 @@
package io.v.nutz.web.commons.shiro.pam;
import io.v.nutz.web.commons.shiro.exception.CaptchaEmptyException;
import io.v.nutz.web.commons.shiro.exception.CaptchaIncorrectException;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.pam.AbstractAuthenticationStrategy;
import org.apache.shiro.realm.Realm;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import java.util.Collection;
@IocBean(name = "authenticationStrategy")
public class AnySuccessfulStrategy extends AbstractAuthenticationStrategy {
/**
* Returns {@code null} immediately, relying on this class's {@link #merge
* merge} implementation to return only the first {@code info} object it
* encounters, ignoring all subsequent ones.
*/
public AuthenticationInfo beforeAllAttempts(Collection<? extends Realm> realms, AuthenticationToken token) throws AuthenticationException {
return null;
}
/**
* Returns the specified {@code aggregate} instance if is non null and valid
* (that is, has principals and they are not empty) immediately, or, if it
* is null or not valid, the {@code info} argument is returned instead.
* <p>
* This logic ensures that the first valid info encountered is the one
* retained and all subsequent ones are ignored, since this strategy
* mandates that only the info from the first successfully authenticated
* realm be used.
*/
protected AuthenticationInfo merge(AuthenticationInfo info, AuthenticationInfo aggregate) {
if (aggregate != null && !Lang.isEmpty(aggregate.getPrincipals())) {
return aggregate;
}
return info != null ? info : aggregate;
}
@Override
public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
if (singleRealmInfo == null) {
if (t.getClass().isAssignableFrom(CaptchaIncorrectException.class)) {
throw Lang.makeThrow(CaptchaIncorrectException.class, t.getMessage());
} else if (t.getClass().isAssignableFrom(CaptchaEmptyException.class)) {
throw Lang.makeThrow(CaptchaEmptyException.class, t.getMessage());
} else if (t.getClass().isAssignableFrom(LockedAccountException.class)) {
throw Lang.makeThrow(LockedAccountException.class, t.getMessage());
} else if (t.getClass().isAssignableFrom(UnknownAccountException.class)) {
throw Lang.makeThrow(UnknownAccountException.class, t.getMessage());
} else if (t.getClass().isAssignableFrom(IncorrectCredentialsException.class)) {
throw Lang.makeThrow(IncorrectCredentialsException.class, t.getMessage());
} else if (t.getClass().isAssignableFrom(ExcessiveAttemptsException.class)) {
throw Lang.makeThrow(ExcessiveAttemptsException.class, t.getMessage());
}
throw Lang.makeThrow(AuthenticationException.class, t.getMessage());
}
return super.afterAttempt(realm, token, singleRealmInfo, aggregateInfo, t);
}
}
@@ -0,0 +1,174 @@
package io.v.nutz.web.commons.shiro.realm;
import cn.hutool.core.util.StrUtil;
import io.v.nutz.base.constant.RedisConstant;
import io.v.nutz.base.utils.LoginUtil;
import io.v.nutz.sys.models.Sys_role;
import io.v.nutz.sys.models.Sys_user;
import io.v.nutz.sys.services.SysRoleService;
import io.v.nutz.sys.services.SysUnionService;
import io.v.nutz.sys.services.SysUserService;
import io.v.nutz.web.commons.ext.validate.ValidateService;
import io.v.nutz.web.commons.shiro.config.EasyCredentialsMatch;
import io.v.nutz.web.commons.shiro.token.PlatformCaptchaToken;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.nutz.castor.Castors;
import org.nutz.dao.Cnd;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
/**
* Created by wizzer on 2017/1/11.
*/
@IocBean(name = "platformRealm")
public class PlatformAuthorizingRealm extends AuthorizingRealm {
private static final Log log = Logs.get();
@Inject
private SysUserService sysUserService;
@Inject
private SysRoleService sysRoleService;
@Inject
private RedisService redisService;
@Inject
private ValidateService validateService;
@Inject
private SysUnionService sysUnionService;
protected SysUserService getUserService() {
return sysUserService;
}
protected SysRoleService getRoleService() {
return sysRoleService;
}
protected RedisService getRedisService() {
return redisService;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
if (token.getClass().isAssignableFrom(PlatformCaptchaToken.class)) {
PlatformCaptchaToken authcToken = (PlatformCaptchaToken) token;
String loginname = authcToken.getUsername();
String captcha = authcToken.getCaptcha();
String key = authcToken.getKey();
LoginUtil.LoginOrigin loginOrigin = authcToken.getLoginOrigin();
Session session = SecurityUtils.getSubject().getSession(true);
if (!loginOrigin.equals(LoginUtil.LoginOrigin.CAS) && !loginOrigin.equals(LoginUtil.LoginOrigin.QI_YE_WEI_XIN)) {
validateService.checkCode(key, captcha);
}
if (Strings.isBlank(loginname)) {
throw Lang.makeThrow(AuthenticationException.class, "登录账号不可为空");
}
Sys_user user = getUserService().fetch(Cnd.NEW().and("loginname", "=", loginname));
if (Lang.isEmpty(user)) {
throw Lang.makeThrow(UnknownAccountException.class, "账号不存在", loginname);
}
// if (user.isDisabled()) {
// throw Lang.makeThrow(LockedAccountException.class, "账号被禁用", loginname);
// }
if (StrUtil.isNotBlank(getRedisService().get(RedisConstant.PLATFORM_REDIS_PREFIX + "platform:userId:" + user.getId()))) {
throw Lang.makeThrow(LockedAccountException.class, "账号被禁用", loginname);
}
if (!loginOrigin.equals(LoginUtil.LoginOrigin.CAS) && !loginOrigin.equals(LoginUtil.LoginOrigin.QI_YE_WEI_XIN)) {
int errCount = NumberUtils.toInt(Strings.sNull(session.getAttribute("platformErrCount")));
if (errCount >= 4) {
//输错5次禁用账户10分钟
// getUserService().update(Chain.make("disabled", 1), Cnd.where("id", "=", user.getId()));
session.setAttribute("platformErrCount", 0);
getRedisService().setex(RedisConstant.PLATFORM_REDIS_PREFIX + "platform:userId:" + user.getId(), 60, user.getId());
throw Lang.makeThrow(LockedAccountException.class, "账号被禁用", loginname);
}
}
//没有错误后完善use信息
getUserService().fetchLinks(user, null);
user = getUserService().fillMenu(user);
user = getUserService().fillModuleMenus(user);
user = getUserService().fillUnitUnion(user);
getRedisService().del(RedisConstant.PLATFORM_REDIS_PREFIX + "platform:userId:" + user.getId());
session.setAttribute("platformErrCount", 0);
session.setAttribute("platform_uid", user.getId());
session.setAttribute("platform_username", user.getUsername());
session.setAttribute("platform_loginname", user.getLoginname());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword().toCharArray(), ByteSource.Util.bytes(user.getSalt()), getName());
info.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));
return info;
}
return null;
}
/**
* 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
Object object = principals.getPrimaryPrincipal();
if (object.getClass().isAssignableFrom(Sys_user.class)) {
Sys_user user = Castors.me().castTo(object, Sys_user.class);
if (!Lang.isEmpty(user) && !user.isDisabled()) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(getUserService().getRoleCodeList(user));
for (Sys_role role : user.getRoles()) {
if (!role.isDisabled())
info.addStringPermissions(getRoleService().getPermissionNameList(role));
}
return info;
} else {
return null;
}
}
return null;
}
public PlatformAuthorizingRealm() {
this(null, null);
}
public PlatformAuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
super(cacheManager, matcher);
// HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
EasyCredentialsMatch hashedCredentialsMatcher = new EasyCredentialsMatch();
hashedCredentialsMatcher.setHashAlgorithmName("SHA-256");
hashedCredentialsMatcher.setHashIterations(1024);
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
setAuthenticationTokenClass(PlatformCaptchaToken.class);
setCredentialsMatcher(hashedCredentialsMatcher);
}
public PlatformAuthorizingRealm(CacheManager cacheManager) {
this(cacheManager, null);
}
public PlatformAuthorizingRealm(CredentialsMatcher matcher) {
this(null, matcher);
}
}
@@ -0,0 +1,16 @@
package io.v.nutz.web.commons.shiro.remember;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
/**
* 由于shiro默认按照jdk生成base64编码cookies策略长度超过4K,造成浏览器无法识别
* 所以已经重写生成cookies策略
* Created by wizzer on 2017/1/18.
*/
public class LightCookieRememberMeManager extends CookieRememberMeManager {
public LightCookieRememberMeManager() {
super();
setSerializer(new SimplePrincipalSerializer());
}
}
@@ -0,0 +1,92 @@
package io.v.nutz.web.commons.shiro.remember;
import org.apache.shiro.io.SerializationException;
import org.apache.shiro.io.Serializer;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import java.io.*;
import java.util.Collection;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* Creates A GZIPed rememberMe cookie, based on the patch for SHIRO-226 (https://issues.apache.org/jira/browse/SHIRO-226)
* Created by wizzer on 2017/1/18.
*/
public class SimplePrincipalSerializer implements Serializer<PrincipalCollection> {
/**
* Magic number to signal that this is a SimplePrincipalSerializer file so that we don't try to decode something crap.
*/
private static final int MAGIC = 0x0BADBEEF;
public byte[] serialize(PrincipalCollection pc) throws SerializationException {
ByteArrayOutputStream ba = new ByteArrayOutputStream();
try {
GZIPOutputStream gout = new GZIPOutputStream(ba);
ObjectOutputStream out = new ObjectOutputStream(gout);
// Write the magic number which allows us to decode it later on
out.writeInt(MAGIC);
// Limited to 32768 realms. Should be enough for everybody.
out.writeShort(pc.getRealmNames().size());
for (String realm : pc.getRealmNames()) {
out.writeUTF(realm);
Collection<?> principals = pc.fromRealm(realm);
// Again, limited to 32768 principals.
out.writeShort(principals.size());
for (Object principal : principals) {
out.writeObject(principal);
}
}
gout.finish();
} catch (IOException e) {
throw new SerializationException(e.getMessage());
}
return ba.toByteArray();
}
public PrincipalCollection deserialize(byte[] serialized) throws SerializationException {
ByteArrayInputStream ba = new ByteArrayInputStream(serialized);
try {
GZIPInputStream gin = new GZIPInputStream(ba);
ObjectInputStream in = new ObjectInputStream(gin);
SimplePrincipalCollection pc = new SimplePrincipalCollection();
// Check magic number
if (in.readInt() != MAGIC)
throw new SerializationException(
"Not valid magic number while deserializing stored PrincipalCollection - possibly obsolete cookie.");
int numRealms = in.readShort();
// realms loop
for (int i = 0; i < numRealms; i++) {
String realmName = in.readUTF();
int numPrincipals = in.readShort();
// principals loop
for (int j = 0; j < numPrincipals; j++) {
Object principal = in.readObject();
pc.add(principal, realmName);
}
}
return pc;
} catch (IOException e) {
throw new SerializationException(e.getMessage());
} catch (ClassNotFoundException e) {
throw new SerializationException(e.getMessage());
}
}
}
@@ -0,0 +1,41 @@
package io.v.nutz.web.commons.shiro.token;
import io.v.nutz.base.utils.LoginUtil;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.shiro.authc.UsernamePasswordToken;
/**
* Created by wizzer on 2017/1/11.
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class PlatformCaptchaToken extends UsernamePasswordToken {
private static final long serialVersionUID = 4676958151524148623L;
private String captcha;
private String key;
private LoginUtil.LoginOrigin loginOrigin;
public PlatformCaptchaToken(String username, String password, boolean rememberMe, String host, String captcha, String key) {
super(username, password, rememberMe, host);
this.captcha = captcha;
this.key = key;
}
public PlatformCaptchaToken(String username, String password, boolean rememberMe, String host, String captcha) {
super(username, password, rememberMe, host);
this.captcha = captcha;
}
/**
* cas免密登录
*
* @param username 用户名
*/
public PlatformCaptchaToken(String username, LoginUtil.LoginOrigin loginOrigin) {
super(username, "", false, null);
this.loginOrigin = loginOrigin;
}
}
@@ -0,0 +1,34 @@
package io.v.nutz.web.commons.slog;
import io.v.nutz.web.commons.slog.annotation.SLog;
import org.nutz.aop.MethodInterceptor;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.aop.SimpleAopMaker;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
/**
* Created by wizzer on 2016/6/22.
*/
@IocBean(name="$aop_syslog")
public class SLogAopConfigration extends SimpleAopMaker<SLog> {
@Inject("refer:$ioc")
protected Ioc ioc;
public List<? extends MethodInterceptor> makeIt(SLog slog, Method method, Ioc ioc) {
return Arrays.asList(new SLogAopInterceptor(ioc, slog, method));
}
public String[] getName() {
return new String[0];
}
public boolean has(String name) {
return false;
}
}
@@ -0,0 +1,88 @@
package io.v.nutz.web.commons.slog;
import io.v.nutz.web.commons.slog.annotation.SLog;
import org.nutz.aop.InterceptorChain;
import org.nutz.aop.MethodInterceptor;
import org.nutz.el.El;
import org.nutz.ioc.Ioc;
import org.nutz.lang.segment.CharSegment;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* Created by wizzer on 2016/6/22.
*/
public class SLogAopInterceptor implements MethodInterceptor {
private static final Log log = Logs.get();
protected SLogService sLogService;
protected String source;
protected String type;
protected String tag;
protected CharSegment seg;
protected boolean param;
protected boolean result;
protected boolean async;
protected Map<String, El> els;
protected Ioc ioc;
public SLogAopInterceptor(Ioc ioc, SLog slog, Method method) {
this.seg = new CharSegment(slog.msg());
if (seg.hasKey()) {
els = new HashMap<String, El>();
for (String key : seg.keys()) {
els.put(key, new El(key));
}
}
this.param = slog.param();
this.result = slog.result();
this.ioc = ioc;
this.source = method.getDeclaringClass().getName() + "#" + method.getName();
this.tag = slog.tag();
SLog _s = method.getDeclaringClass().getAnnotation(SLog.class);
if (_s != null) {
this.tag = _s.tag() + "," + this.tag;
}
this.type = slog.type();
this.async = slog.async();
}
public void filter(InterceptorChain chain) throws Throwable {
try {
chain.doChain();
doLog("aop.after", seg, chain, null);
} catch (Throwable e) {
doLog("aop.error", seg, chain, e);
throw e;
}
}
protected void doLog(String t, CharSegment seg, InterceptorChain chain, Throwable e) {
if (sLogService == null)
sLogService = ioc.get(SLogService.class);
try {
sLogService.log(t,
type,
tag,
source,
seg,
els,
param,
result,
async,
chain.getArgs(),
chain.getReturn(),
chain.getCallingMethod(),
chain.getCallingObj(),
e);
} catch (Exception e1) {
log.debug("slog fail", e1);
}
}
}
@@ -0,0 +1,230 @@
package io.v.nutz.web.commons.slog;
import io.v.nutz.sys.models.Sys_log;
import io.v.nutz.sys.services.SysLogService;
import io.v.nutz.web.commons.utils.ShiroUtil;
import org.nutz.Nutz;
import org.nutz.el.El;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.segment.CharSegment;
import org.nutz.lang.util.ClassMetaReader;
import org.nutz.lang.util.Context;
import org.nutz.lang.util.MethodParamNamesScaner;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* Created by wizzer on 2016/6/22.
*/
@IocBean(create = "init", depose = "close")
public class SLogService implements Runnable {
private static final Log log = Logs.get();
ExecutorService es;
LinkedBlockingQueue<Sys_log> queue;
@Inject
protected SysLogService sysLogService;
/**
* 异步插入日志
*
* @param syslog 日志对象
*/
public void async(Sys_log syslog) {
LinkedBlockingQueue<Sys_log> queue = this.queue;
if (queue != null)
try {
boolean re = queue.offer(syslog, 50, TimeUnit.MILLISECONDS);
if (!re) {
log.info("syslog queue is full, drop it ...");
}
} catch (InterruptedException e) {
}
}
/**
* 同步插入日志
*
* @param syslog 日志对象
*/
public void sync(Sys_log syslog) {
try {
sysLogService.fastInsertSysLog(syslog);
} catch (Throwable e) {
log.info("insert syslog sync fail", e);
}
}
public void run() {
while (true) {
LinkedBlockingQueue<Sys_log> queue = this.queue;
if (queue == null)
break;
try {
Sys_log sysLog = queue.poll(1, TimeUnit.SECONDS);
if (sysLog != null) {
sync(sysLog);
}
} catch (InterruptedException e) {
break;
}
}
}
/**
* 本方法通常由aop拦截器调用.
*
* @param t 日志类型
* @param tag 标签
* @param source 源码位置
* @param els 消息模板的EL表达式预处理表
* @param param 是否异步插入
* @param result 是否异步插入
* @param async 是否异步插入
* @param args 方法参数
* @param re 方法返回值
* @param method 方法实例
* @param obj 被拦截的对象
* @param e 异常对象
*/
public void log(String t, String type, String tag, String source, CharSegment seg,
Map<String, El> els, boolean param, boolean result,
boolean async,
Object[] args, Object re, Method method, Object obj,
Throwable e) {
String _msg = null;
if (seg.hasKey()) {
Context ctx = Lang.context();
List<String> names = null;
if (Nutz.majorVersion() == 1 && Nutz.minorVersion() < 60) {
Class<?> klass = obj.getClass();
if (klass.getName().endsWith("$$NUTZAOP"))
klass = klass.getSuperclass();
String key = klass.getName();
if (caches.containsKey(key))
names = caches.get(key).get(ClassMetaReader.getKey(method));
else {
try {
Map<String, List<String>> tmp = MethodParamNamesScaner.getParamNames(klass);
names = tmp.get(ClassMetaReader.getKey(method));
caches.put(key, tmp);
} catch (IOException e1) {
log.debug("error when reading param name");
}
}
} else {
names = MethodParamNamesScaner.getParamNames(method);
}
if (names != null) {
for (int i = 0; i < names.size() && i < args.length; i++) {
ctx.set(names.get(i), args[i]);
}
}
ctx.set("obj", obj);
ctx.set("args", args);
ctx.set("re", re);
ctx.set("return", re);
ctx.set("req", Mvcs.getReq());
ctx.set("resp", Mvcs.getResp());
Context _ctx = Lang.context();
for (String key : seg.keys()) {
_ctx.set(key, els.get(key).eval(ctx));
}
_msg = seg.render(_ctx).toString();
} else {
_msg = seg.getOrginalString();
}
String _param = "";
String _result = "";
if (param && args != null) {
try {
_param = Json.toJson(args);
} catch (Exception e1) {
_param = "传参不能转换为JSON格式";
}
}
if (result && re != null) {
try {
_result = Json.toJson(re);
} catch (Exception e1) {
_param = "返回对象不能转换为JSON格式";
}
}
log(type, tag, source, _msg, async, _param, _result);
}
public void log(String type, String tag, String source, String msg, boolean async, String param, String result) {
Sys_log slog = makeLog(type, tag, source, msg, param, result);
if (async)
async(slog);
else
sync(slog);
}
protected static Map<String, Map<String, List<String>>> caches = new HashMap<String, Map<String, List<String>>>();
public void init() {
queue = new LinkedBlockingQueue<Sys_log>();
int c = Runtime.getRuntime().availableProcessors();
es = Executors.newFixedThreadPool(c);
for (int i = 0; i < c; i++) {
es.submit(this);
}
}
public void close() throws InterruptedException {
queue = null; // 触发关闭
if (es != null && !es.isShutdown()) {
es.shutdown();
es.awaitTermination(5, TimeUnit.SECONDS);
}
}
public static Sys_log makeLog(String type, String tag, String source, String msg, String param, String result) {
Sys_log sysLog = new Sys_log();
if (type == null || tag == null) {
throw new RuntimeException("type/tag can't null");
}
if (source == null) {
StackTraceElement[] tmp = Thread.currentThread().getStackTrace();
if (tmp.length > 2) {
source = tmp[2].getClassName() + "#" + tmp[2].getMethodName();
} else {
source = "main";
}
}
sysLog.setType(type);
sysLog.setTag(tag);
sysLog.setSrc(source);
sysLog.setMsg(msg);
sysLog.setParam(param);
sysLog.setResult(result);
if (Mvcs.getReq() != null) {
sysLog.setIp(Lang.getIP(Mvcs.getReq()));
}
sysLog.setCreatedBy(ShiroUtil.getPlatformUid());
sysLog.setDelFlag(false);
sysLog.setUsername(ShiroUtil.getPlatformUsername());
sysLog.setLoginname(ShiroUtil.getPlatformLoginname());
return sysLog;
}
}
@@ -0,0 +1,40 @@
package io.v.nutz.web.commons.slog.annotation;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface SLog {
String type() default "platform";
/**
* 标签
*
* @return
*/
String tag();
String msg() default "";
/**
* 是否记录传递参数
*
* @return 消息模板
*/
boolean param() default false;
/**
* 记录执行结果
*
* @return 消息模板
*/
boolean result() default false;
/**
* 是否异步执行,默认为true
*
* @return true, 如果需要异步执行
*/
boolean async() default true;
}
@@ -0,0 +1,199 @@
package io.v.nutz.web.commons.utils;
import com.artofsolving.jodconverter.DocumentConverter;
import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter;
import java.io.*;
/**
* 文档转换util
*/
public class DocConverter {
private static final int environment = 1;// 环境1windows,2:linux(涉及pdf2swf路径问题)
private String fileString;
private String outputPath = "";// 输入路径,如果不设置就输出在默认位置
private String fileName;
private File pdfFile;
private File swfFile;
private File docFile;
public DocConverter(String fileString) {
ini(fileString);
}
/*
* 重新设置 file @param fileString
*/
public void setFile(String fileString) {
ini(fileString);
}
/*
* 初始化 @param fileString
*/
private void ini(String fileString) {
this.fileString = fileString;
fileName = fileString.substring(0, fileString.lastIndexOf("."));
docFile = new File(fileString);
pdfFile = new File(fileName + ".pdf");
swfFile = new File(fileName + ".swf");
}
/*
* 转为PDF @param file
*/
private void doc2pdf() throws Exception {
if (docFile.exists()) {
if (!pdfFile.exists()) {
OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);
try {
connection.connect();
DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
converter.convert(docFile, pdfFile);
// close the connection
connection.disconnect();
System.out.println("****pdf转换成功,PDF输出:" + pdfFile.getPath() + "****");
} catch (java.net.ConnectException e) {
// ToDo Auto-generated catch block
e.printStackTrace();
System.out.println("****swf转换异常,openoffice服务未启动!****");
throw e;
} catch (com.artofsolving.jodconverter.openoffice.connection.OpenOfficeException e) {
e.printStackTrace();
System.out.println("****swf转换器异常,读取转换文件失败****");
throw e;
} catch (Exception e) {
e.printStackTrace();
throw e;
}
} else {
System.out.println("****已经转换为pdf,不需要再进行转化****");
}
} else {
System.out.println("****swf转换器异常,需要转换的文档不存在,无法转换****");
}
}
/*
* 转换成swf
*/
private void pdf2swf() throws Exception {
Runtime r = Runtime.getRuntime();
if (!swfFile.exists()) {
if (pdfFile.exists()) {
if (environment == 1)// windows环境处理
{
try {
// 这里根据SWFTools安装路径需要进行相应更改
Process p = r.exec("D:\\ewm\\hj\\pdf2swf\\pdf2swf.exe " + pdfFile.getPath() + " -o " + swfFile.getPath() + " -T 9");
System.out.print(loadStream(p.getInputStream()));
System.err.print(loadStream(p.getErrorStream()));
System.out.print(loadStream(p.getInputStream()));
System.err.println("****swf转换成功,文件输出:" + swfFile.getPath() + "****");
// if (pdfFile.exists()) {
// pdfFile.delete();
// }
} catch (Exception e) {
e.printStackTrace();
throw e;
}
} else if (environment == 2)// linux环境处理
{
try {
Process p = r.exec("pdf2swf " + pdfFile.getPath() + " -o " + swfFile.getPath() + " -T 9");
System.out.print(loadStream(p.getInputStream()));
System.err.print(loadStream(p.getErrorStream()));
System.err.println("****swf转换成功,文件输出:" + swfFile.getPath() + "****");
if (pdfFile.exists()) {
pdfFile.delete();
}
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
} else {
System.out.println("****pdf不存在,无法转换****");
}
} else {
System.out.println("****swf已存在不需要转换****");
}
}
static String loadStream(InputStream in) throws IOException {
int ptr = 0;
//把InputStream字节流 替换为BufferedReader字符流 2013-07-17修改
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder buffer = new StringBuilder();
while ((ptr = reader.read()) != -1) {
buffer.append((char) ptr);
}
return buffer.toString();
}
/*
* 转换主方法
*/
public boolean conver() {
if (swfFile.exists()) {
System.out.println("****swf转换器开始工作,该文件已经转换为swf****");
return true;
}
if (environment == 1) {
System.out.println("****swf转换器开始工作,当前设置运行环境windows****");
} else {
System.out.println("****swf转换器开始工作,当前设置运行环境linux****");
}
try {
doc2pdf();
pdf2swf();
} catch (Exception e) {
// TODO: Auto-generated catch block
e.printStackTrace();
return false;
}
if (swfFile.exists()) {
return true;
} else {
return false;
}
}
/*
* 返回文件路径 @param s
*/
public String getswfPath() {
if (swfFile.exists()) {
String tempString = swfFile.getPath();
tempString = tempString.replaceAll("\\\\", "/");
return tempString;
} else {
return "";
}
}
/*
* 设置输出路径
*/
public void setOutputPath(String outputPath) {
this.outputPath = outputPath;
if (!outputPath.equals("")) {
String realName = fileName.substring(fileName.lastIndexOf("/"), fileName.lastIndexOf("."));
if (outputPath.charAt(outputPath.length()) == '/') {
swfFile = new File(outputPath + realName + ".swf");
} else {
swfFile = new File(outputPath + realName + ".swf");
}
}
}
public static void main(String s[]) {
DocConverter d = new DocConverter("C:\\Users\\mayn\\Desktop\\安全管理系统.docx");
d.conver();
}
}
@@ -0,0 +1,102 @@
package io.v.nutz.web.commons.utils;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @Author: 1V
* @DateTime: 2020/12/13 17:07
* @Description: TODO
*/
public class FileUtil {
private final static Log log = Logs.get();
/**
* 压缩文件
*
* @param sourceFilePath 源文件路径
* @param zipFilePath 压缩后文件存储路径
* @param zipFilename 压缩文件名
*/
public static void compressToZip(String sourceFilePath, String zipFilePath, String zipFilename) {
File sourceFile = new File(sourceFilePath);
File zipPath = new File(zipFilePath);
if (!zipPath.exists()) {
zipPath.mkdirs();
}
File zipFile = new File(zipPath + File.separator + zipFilename);
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
writeZip(sourceFile, "", zos);
//文件压缩完成后,删除被压缩文件
boolean flag = deleteDir(sourceFile);
log.infof("删除被压缩文件[" + sourceFile + "]标志:{}", flag);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage(), e.getCause());
}
}
/**
* 遍历所有文件,压缩
*
* @param file 源文件目录
* @param parentPath 压缩文件目录
* @param zos 文件流
*/
public static void writeZip(File file, String parentPath, ZipOutputStream zos) {
if (file.isDirectory()) {
//目录
parentPath += file.getName() + File.separator;
File[] files = file.listFiles();
for (File f : files) {
writeZip(f, parentPath, zos);
}
} else {
//文件
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
//指定zip文件夹
ZipEntry zipEntry = new ZipEntry(parentPath + file.getName());
zos.putNextEntry(zipEntry);
int len;
byte[] buffer = new byte[1024 * 10];
while ((len = bis.read(buffer, 0, buffer.length)) != -1) {
zos.write(buffer, 0, len);
zos.flush();
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage(), e.getCause());
}
}
}
/**
* 删除文件夹
*
* @param dir
* @return
*/
public static boolean deleteDir(File dir) {
if (dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
//删除空文件夹
return dir.delete();
}
}
@@ -0,0 +1,439 @@
package io.v.nutz.web.commons.utils;
import io.v.nutz.base.utils.Roles;
import io.v.nutz.sys.models.Sys_menu;
import io.v.nutz.sys.models.Sys_user;
import io.v.nutz.sys.models.Sys_user_role;
import io.v.nutz.sys.services.SysUserService;
import io.v.nutz.sys.services.impl.SysUserServiceImpl;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.mvc.Mvcs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* Created by wizzer on 2017/1/16.
*/
public class ShiroUtil {
private static final String ROLE_NAMES_DELIMETER = ",";
private static final String PERMISSION_NAMES_DELIMETER = ",";
private static final Logger logger = LoggerFactory.getLogger(ShiroUtil.class);
/**
* 获取平台当前登录用户的所在单位
*
* @return
*/
public static String getPlatformUserUnitid() {
try {
Subject subject = SecurityUtils.getSubject();
if (subject != null) {
Sys_user user = (Sys_user) subject.getPrincipal();
if (user != null) {
return Strings.sNull(user.getUnitid());
}
}
} catch (Exception e) {
}
return "";
}
/**
* 获取平台后台登陆UID
*
* @return
*/
public static String getPlatformUid() {
try {
HttpServletRequest request = Mvcs.getReq();
if (request != null) {
return Strings.sNull(request.getSession(true).getAttribute("platform_uid"));
}
} catch (Exception e) {
}
return "";
}
/**
* 获取平台后台登陆用户名称
*
* @return
*/
public static String getPlatformLoginname() {
try {
HttpServletRequest request = Mvcs.getReq();
if (request != null) {
return Strings.sNull(request.getSession(true).getAttribute("platform_loginname"));
}
} catch (Exception e) {
}
return "";
}
/**
* 获取平台后台登陆用户名称
*
* @return
*/
public static String getPlatformUsername() {
try {
HttpServletRequest request = Mvcs.getReq();
if (request != null) {
return Strings.sNull(request.getSession(true).getAttribute("platform_username"));
}
} catch (Exception e) {
}
return "";
}
/**
* 验证是否为已认证通过的用户,不包含已记住的用户,这是与 isUser 标签方法的区别所在
*
* @return 用户是否已通过认证
*/
public static boolean isAuthenticated() {
Subject subject = SecurityUtils.getSubject();
return subject != null && subject.isAuthenticated() == true;
}
/**
* 验证是否为未认证通过用户,与 isAuthenticated 标签相对应,与 isGuest 标签的区别是,该标签包含已记住用户
*
* @return 用户是否未通过认证
*/
public static boolean isNotAuthenticated() {
Subject subject = SecurityUtils.getSubject();
return subject == null || subject.isAuthenticated() == false;
}
/**
* 验证用户是否为访客,即未认证(包含未记住)的用户
*
* @return 用户是否为访客
*/
public static boolean isGuest() {
Subject subject = SecurityUtils.getSubject();
return subject == null || subject.getPrincipal() == null;
}
/**
* 验证用户是否认证通过或已记住的用户
*
* @return 用户是否认证通过或已记住的用户
*/
public static boolean isUser() {
Subject subject = SecurityUtils.getSubject();
return subject != null && subject.getPrincipal() != null;
}
/**
* 返回用户 Principal
*
* @return 用户 Principal
*/
public static Object getPrincipal() {
Subject subject = SecurityUtils.getSubject();
return subject != null ? subject.getPrincipal() : null;
}
/**
* 返回用户属性
*
* @param property 属性名称
* @return 用户属性
*/
public static Object getPrincipalProperty(String property) {
Subject subject = SecurityUtils.getSubject();
if (subject != null) {
Object principal = subject.getPrincipal();
try {
BeanInfo bi = Introspector.getBeanInfo(principal.getClass());
for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
if (pd.getName().equals(property) == true) {
return pd.getReadMethod().invoke(principal, (Object[]) null);
}
}
logger.trace("Property [{}] not found in principal of type [{}]", property,
principal.getClass().getName());
} catch (Exception e) {
logger.trace("Error reading property [{}] from principal of type [{}]", property,
principal.getClass().getName());
}
}
return null;
}
/**
* 返回用户属性 json格式 懂得都懂
*
* @param property
* @return
*/
public static String getPrincipalPropertyJson(String property) {
return Json.toJson(getPrincipalProperty(property));
}
/**
* 验证用户是否具备某角色。
*
* @param role 角色名称
* @return 用户是否具备某角色
*/
public static boolean hasRole(String role) {
Subject subject = SecurityUtils.getSubject();
return subject != null && subject.hasRole(role) == true;
}
/**
* 验证用户是否不具备某角色,与 hasRole 逻辑相反。
*
* @param role 角色名称
* @return 用户是否不具备某角色
*/
public static boolean lacksRole(String role) {
return hasRole(role) != true;
}
/**
* 验证用户是否具有以下任意一个角色。
*
* @param roleNames 以 delimeter 为分隔符的角色列表
* @param delimeter 角色列表分隔符
* @return 用户是否具有以下任意一个角色
*/
public static boolean hasAnyRoles(String roleNames, String delimeter) {
Subject subject = SecurityUtils.getSubject();
if (subject != null) {
if (delimeter == null || delimeter.length() == 0) {
delimeter = ROLE_NAMES_DELIMETER;
}
for (String role : roleNames.split(delimeter)) {
if (subject.hasRole(role.trim()) == true) {
return true;
}
}
}
return false;
}
/**
* 验证用户是否具有以下任意一个角色。
*
* @param roleNames 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表
* @return 用户是否具有以下任意一个角色
*/
public static boolean hasAnyRoles(String roleNames) {
return hasAnyRoles(roleNames, ROLE_NAMES_DELIMETER);
}
/**
* 验证用户是否具有以下任意一个角色。
*
* @param roleNames 角色列表
* @return 用户是否具有以下任意一个角色
*/
public static boolean hasAnyRoles(Collection<String> roleNames) {
Subject subject = SecurityUtils.getSubject();
if (subject != null && roleNames != null) {
for (String role : roleNames) {
if (role != null && subject.hasRole(role.trim()) == true) {
return true;
}
}
}
return false;
}
/**
* 验证用户是否具有以下任意一个角色。
*
* @param roleNames 角色列表
* @return 用户是否具有以下任意一个角色
*/
public static boolean hasAnyRoles(String[] roleNames) {
Subject subject = SecurityUtils.getSubject();
if (subject != null && roleNames != null) {
for (int i = 0; i < roleNames.length; i++) {
String role = roleNames[i];
if (role != null && subject.hasRole(role.trim()) == true) {
return true;
}
}
}
return false;
}
/**
* 验证用户是否具备某权限。
*
* @param permission 权限名称
* @return 用户是否具备某权限
*/
public static boolean hasPermission(String permission) {
Subject subject = SecurityUtils.getSubject();
return subject != null && subject.isPermitted(permission);
}
/**
* 验证用户是否不具备某权限,与 hasPermission 逻辑相反。
*
* @param permission 权限名称
* @return 用户是否不具备某权限
*/
public static boolean lacksPermission(String permission) {
return hasPermission(permission) != true;
}
/**
* 验证用户是否具有以下任意一个权限。
*
* @param permissions 以 delimeter 为分隔符的权限列表
* @param delimeter 权限列表分隔符
* @return 用户是否具有以下任意一个权限
*/
public static boolean hasAnyPermissions(String permissions, String delimeter) {
Subject subject = SecurityUtils.getSubject();
if (subject != null) {
if (delimeter == null || delimeter.length() == 0) {
delimeter = PERMISSION_NAMES_DELIMETER;
}
for (String permission : permissions.split(delimeter)) {
if (permission != null && subject.isPermitted(permission.trim()) == true) {
return true;
}
}
}
return false;
}
/**
* 验证用户是否具有以下任意一个权限。
*
* @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表
* @return 用户是否具有以下任意一个权限
*/
public static boolean hasAnyPermissions(String permissions) {
return hasAnyPermissions(permissions, PERMISSION_NAMES_DELIMETER);
}
/**
* 验证用户是否具有以下任意一个权限。
*
* @param permissions 权限列表
* @return 用户是否具有以下任意一个权限
*/
public static boolean hasAnyPermissions(Collection<String> permissions) {
Subject subject = SecurityUtils.getSubject();
if (subject != null && permissions != null) {
for (String permission : permissions) {
if (permission != null && subject.isPermitted(permission.trim()) == true) {
return true;
}
}
}
return false;
}
/**
* 验证用户是否具有以下任意一个权限。
*
* @param permissions 权限列表
* @return 用户是否具有以下任意一个权限
*/
public static boolean hasAnyPermissions(String[] permissions) {
Subject subject = SecurityUtils.getSubject();
if (subject != null && permissions != null) {
for (int i = 0; i < permissions.length; i++) {
String permission = permissions[i];
if (permission != null && subject.isPermitted(permission.trim()) == true) {
return true;
}
}
}
return false;
}
/**
* 获取当前实例sessionId
*
* @return
*/
public static String getSessionId() {
Subject subject = SecurityUtils.getSubject();
return (String) subject.getSession().getId();
}
public static String getUserId() {
return getPlatformUid();
}
public static String getUnitId() {
return (String) getPrincipalProperty("unitid");
}
/**
* 获取工会小组id
*/
public static List<String> getUnionGroupIds() {
Dao dao = Mvcs.getIoc().get(Dao.class);
List<Sys_user_role> userRole = dao.query(Sys_user_role.class, Cnd.where("roleId", "=", Roles.ghxzzz)
.and("userId", "=", getPrincipalProperty("id")));
List<String> ids = userRole.stream().map(Sys_user_role::getUnionGroupId).collect(Collectors.toList());
return Lang.isNotEmpty(ids) ? ids : null;
}
/**
* 用户模块菜单
*
* @return {@link String}
*/
public static String userModuleMenus() {
List<Sys_menu> menus = (List<Sys_menu>) getPrincipalProperty("moduleMenus");
if (Lang.isEmpty(menus)) {
SysUserService sysUserService = Mvcs.getIoc().get(SysUserServiceImpl.class);
sysUserService.deleteCacheAndUpdate(getUserId());
menus = (List<Sys_menu>) getPrincipalProperty("moduleMenus");
return Json.toJson(menus);
}
return Json.toJson(menus);
}
}