map = new HashMap<>();
+ map.put("username","15808234569");
+ map.put("apiKey","gaoxingongyuanchengshiju");
+ String s = JSONUtil.toJsonPrettyStr(map);
+ String doEncrypt = Sm2.doEncrypt(s, publicKey);
+// String result2 = HttpRequest.post("https://dbxqtalents.cn/gx-api/userOpenLogin")
+// String result2 = HttpRequest.post("http://192.168.0.54:8084/userOpenLogin")
+ String result2 = HttpRequest.post("http://ljlcom.gnway.cc/userOpenLogin")
+ .header("Referer","https://dbxqtalents.cn/gx-api")
+ .header("path","/userOpenLogin")
+ .header("targe","weixin")
+ .header("Authorization","Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJhcHBfdXNlcjo0Mzc4OSIsInJuU3RyIjoiV05XZFFnaHpHYlRRRU5ObVpwbmhaaFp6MmtKaWtSR0MiLCJ1c2VySWQiOjQzNzg5fQ.QCsN3iIFk38dzTvXITGx2wV5c9kdPdvWZs7gjf6dFzc")
+ .header("method","POST")
+ .body(doEncrypt,"application/json")
+ .execute().body();
+ System.out.println("result2 = " + result2);
+ }
+
+ /**
+ * 图片导出
+ *
+ * 1. 创建excel对应的实体对象 参照{@link ImageDemoData}
+ *
+ * 2. 直接写即可
+ */
+ @Test
+ public void imageWrite() throws Exception {
+ String fileName = "E:\\"+ System.currentTimeMillis() + ".xlsx";
+
+ // 这里注意下 所有的图片都会放到内存 暂时没有很好的解法,大量图片的情况下建议 2选1:
+ // 1. 将图片上传到oss 或者其他存储网站: https://www.aliyun.com/product/oss ,然后直接放链接
+ // 2. 使用: https://github.com/coobird/thumbnailator 或者其他工具压缩图片
+ String imagePath = "https://gx.chengdutalent.cn:8010/upload/GXTalents/images/f264ec41dcfb47b9b6ef231441d3123b.png";
+ try {
+ List list = ListUtils.newArrayList();
+ ImageDemoData imageDemoData = new ImageDemoData();
+ list.add(imageDemoData);
+ // 放入五种类型的图片 实际使用只要选一种即可
+// imageDemoData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath)));
+// imageDemoData.setFile(new File(imagePath));
+// imageDemoData.setString(imagePath);
+// imageDemoData.setInputStream(inputStream);
+ imageDemoData.setUrl(new URL(
+ "https://gx.chengdutalent.cn:8010/upload/GXTalents/images/f264ec41dcfb47b9b6ef231441d3123b.png"));
+
+ // 这里演示
+ // 需要额外放入文字
+ // 而且需要放入2个图片
+ // 第一个图片靠左
+ // 第二个靠右 而且要额外的占用他后面的单元格
+ /*WriteCellData writeCellData = new WriteCellData<>();
+ imageDemoData.setWriteCellDataFile(writeCellData);
+ // 这里可以设置为 EMPTY 则代表不需要其他数据了
+ writeCellData.setType(CellDataTypeEnum.STRING);
+ writeCellData.setStringValue("额外的放一些文字");*/
+
+ /*// 可以放入多个图片
+ List imageDataList = new ArrayList<>();
+ ImageData imageData = new ImageData();
+ imageDataList.add(imageData);
+ writeCellData.setImageDataList(imageDataList);
+ // 放入2进制图片
+ imageData.setImage(FileUtils.readFileToByteArray(new File(imagePath)));
+ // 图片类型
+ imageData.setImageType(ImageData.ImageType.PICTURE_TYPE_PNG);
+ // 上 右 下 左 需要留空
+ // 这个类似于 css 的 margin
+ // 这里实测 不能设置太大 超过单元格原始大小后 打开会提示修复。暂时未找到很好的解法。
+ imageData.setTop(5);
+ imageData.setRight(40);
+ imageData.setBottom(5);
+ imageData.setLeft(5);
+
+ // 放入第二个图片
+ imageData = new ImageData();
+ imageDataList.add(imageData);
+ writeCellData.setImageDataList(imageDataList);
+ imageData.setImage(FileUtils.readFileToByteArray(new File(imagePath)));
+ imageData.setImageType(ImageData.ImageType.PICTURE_TYPE_PNG);
+ imageData.setTop(5);
+ imageData.setRight(5);
+ imageData.setBottom(5);
+ imageData.setLeft(50);
+ // 设置图片的位置 假设 现在目标 是 覆盖 当前单元格 和当前单元格右边的单元格
+ // 起点相对于当前单元格为0 当然可以不写
+ imageData.setRelativeFirstRowIndex(0);
+ imageData.setRelativeFirstColumnIndex(0);
+ imageData.setRelativeLastRowIndex(0);
+ // 前面3个可以不写 下面这个需要写 也就是 结尾 需要相对当前单元格 往右移动一格
+ // 也就是说 这个图片会覆盖当前单元格和 后面的那一格
+ imageData.setRelativeLastColumnIndex(1);*/
+
+ // 写入数据
+ EasyExcel.write(fileName, ImageDemoData.class).sheet().doWrite(list);
+ }catch (Exception e){
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ public void test0121123(){
+ HashMap hashMap = new HashMap<>();
+ hashMap.put("id","3212");
+ hashMap.put("status","00D");
+ hashMap.put("description","测试");
+ hashMap.put("auditDepartName","数字经济局功能区建设推进处");
+ housingConstructionBureauPushDto.send3(hashMap,"https://www.cdhtrct.com/route/open/api/anju/openBuyHousesCallback");
+ }
+
+ @Test
+ public void test15234523(){
+// providerCustomer.sendDelayMsg("延迟队列测试",3);
+ String msg ="我来了";
+ /* MessageProperties messageProperties = new MessageProperties();
+ messageProperties.setHeader("x-delay",5000);//延迟5秒被删除
+ Message message = new Message(msg.getBytes(), messageProperties);
+ amqpTemplate.convertAndSend("PLUGIN_DELAY_EXCHANGE","delay","123132");//交换机和路由键必须和配置文件类中保持一致
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ System.out.println("消息发送成功【" + sdf.format(new Date()) + "】");*/
+// orderService.makeOrder();
+ }
+
+ @Test
+ public void testt12333(){
+ double div = NumberUtil.div(28, 3000);
+ System.out.println("div = " + div);
+ String s = NumberUtil.decimalFormat("#.##%", div);
+ System.out.println("s = " + s);
+ //获取二期认定通过人才数
+ /*List housesReviewList = housesReviewMapper.selectList(new LambdaQueryWrapper<>(HousesReview.class)
+ .eq(HousesReview::getProcessStatus, Constants.SUCCEED));
+ //获取本月复审通过数
+ Date date = DateUtil.date();
+ //获得月份,从0开始计数
+ int month = DateUtil.month(date);
+ housesReviewList.forEach(h ->{
+ int month1 = h.getPassTime().getMonth();
+ System.out.println("month1 = " + month1);
+ String s = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, h.getPassTime());
+ System.out.println("s = " + s);
+ });*/
+// List collect = housesReviewList.stream().filter(h -> h.getPassTime().getMonth() == month).collect(Collectors.toList());
+// System.out.println("collect = " + collect);
+ }
+
+ /**
+ * 获取公钥和私钥
+ */
+ @Test
+ public void test0004(){
+ /*Keypair keypair = Sm2.generateKeyPairHex();
+ String publicKey = keypair.getPublicKey();
+ System.out.println("publicKey = " + publicKey);
+
+ String privateKey = keypair.getPrivateKey();
+ System.out.println("privateKey = " + privateKey);*/
+// String substring = DesensitizedUtil.idCardNum("510503199602214055", 4, 0).substring(0, 9);
+// System.out.println("card = " + substring);
+
+ String str ="https://gx.chengdutalent.cn:8010/upload/GXTalents/images/a6b742bc7843405da406b0159179dcfd.jpg";
+ String substring = str.substring(str.lastIndexOf("/") + 1);
+
+ String txt ="https://rcaj.cdhtgycs.cn/images/2023/07/01/"+substring;
+ buyHousesService.excelZip("");
+ System.out.println("txt = " + txt);
+
+ }
+
+ @Test
+ public void TestMessageAck() throws UnsupportedEncodingException {
+
+ String msg="A 类";
+ String trim = StringUtils.trimAllWhitespace(msg);
+ int length = trim.length();
+ System.out.println("length = " + length);
+// Message build = MessageBuilder.withBody(msg.getBytes()).build();
+// build.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
+// build.getMessageProperties().setDelay(50000);
+// amqpTemplate.convertAndSend(TalentsDelayRabbitConfig.TALENTS_PLUGIN_DELAY_EXCHANGE,TalentsDelayRabbitConfig.TALENTS_PLUGIN_DELAY_KEY,build);
+ }
+
+ @Test
+ public void testPush() throws ParseException {
+ Map map = WorkUtils.getInfoToMap("buy_houses","3218");
+ String virtualcode = String.valueOf(map.get("virtualcode"));
+ map.put("virtualcode", virtualcode == "3" ? "010" : "009");
+ String cardType = String.valueOf(map.get("nationality"));
+ map.put("cardType", "中国籍".equals(cardType) ? 1 : 4);
+ Object createTime = map.get("createTime");
+ SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH);
+ DateFormat cst = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ Date format = sdf.parse(createTime.toString());
+ String dateString = cst.format(format);
+ map.put("qyStatus", "4");
+ map.put("creatTime",dateString);
+ map.put("gyStatus", "4");
+ map.put("shStatus", "4");
+ map.put("buyHousesMemberList", "null");
+ map.put("buyHousesLogList", "null");
+ String s = housingConstructionBureauPushDto.openUrl("https://171.221.172.13:8088/CCSRegistryCenter/rest", map, "253");
+ }
+ @Test
+ public void testOut(){
+ BuyHouses buyHouses = buyHousesMapper.selectById(3218);
+ Map map = new HashMap<>();
+ map.put("id",buyHouses.getId());
+ map.put("reason","人才主动提交");//原因
+ map.put("userName",buyHouses.getUserName());
+ map.put("cardId",buyHouses.getCardId());
+ map.put("cancelTime", DateUtils.dateTime("yyyy-MM-dd HH:mm:ss"));
+ map.put("note","人才主动撤销");//备注
+ map.put("status", "00N");
+ System.out.println("JSONUtil.toJsonPrettyStr(map) = " + JSONUtil.toJsonPrettyStr(map));
+ housingConstructionBureauPushDto.openUrl("https://jcfw.cdzjryb.com/CCSRegistryCenter/rest",map,"254");//正式
+ }
+
+ @Test
+ public void paChon() throws Exception {
+// R rInfo = OpenUtils.getGaoXinCardInfo("510503199602214055");
+// System.out.println("rInfo = " + rInfo);
+ String s = com.ruoyi.common.utils.StringUtils.toUpperCase("510503199602214055l");
+ System.out.println("s = " + s);
+// buyHousesService.logout("3184");
+
+// R gaoXinCardInfo = OpenUtils.getGaoXinCardInfo("510503199602214055");
+// System.out.println("JSONUtil.toJsonPrettyStr(gaoXinCardInfo) = " + JSONUtil.toJsonPrettyStr(gaoXinCardInfo));
+ /* String appsecret ="JXYB7KpXlH9i0CL6";
+ String aesKey = "74242EAFE97F18BFAE9D2682590B6614";
+ String iv = "74242EAFE97F18BF";
+ String id="2023062804031";
+ String url ="http://162.14.100.54:9010/index.php/Api/renju/get_user_info";
+ AES aes = new AES(Mode.CBC, Padding.PKCS5Padding,aesKey.getBytes(),iv.getBytes());
+ String param=aes.encryptBase64(
+ new JSONObject()
+ .set("id_card","510503199602214056")
+ .toStringPretty());
+ MD5 md5 = SecureUtil.md5();
+ String content=id+param+appsecret;
+ String sign=md5.digestHex(content);
+ JSONObject jsonObject = new JSONObject()
+ .set("id",id)
+ .set("param",param)
+ .set("sign",sign);
+ String listContent = HttpRequest.post(url)
+ .body(jsonObject.toStringPretty())
+ .execute()
+ .body();
+ System.out.println("listContent = " + listContent);*/
+
+ }
+
+ @Test
+ public void test45656() {
+ HttpRequest.get("https://rcaj.cdhtgycs.cn/gx-api/user/house/excelZip?id=3136")
+ .header("Referer", "https://rcaj.cdhtgycs.cn")
+ .execute()
+ .body();
+ }
+
+ @Test
+ public void testtttt(HttpServletResponse response) throws IOException {
+ response.sendRedirect("https://dbxqtalents.cn/111.html");
+
+ }
}
+
diff --git a/ruoyi-admin/src/test/java/com/ruoyi/test/HttpReq.java b/ruoyi-admin/src/test/java/com/ruoyi/test/HttpReq.java
new file mode 100644
index 000000000..4f871b9a3
--- /dev/null
+++ b/ruoyi-admin/src/test/java/com/ruoyi/test/HttpReq.java
@@ -0,0 +1,179 @@
+package com.ruoyi.test;
+
+import cn.hutool.http.HttpUtil;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Node;
+import org.jsoup.select.Elements;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+public class HttpReq {
+
+ //private OkHttpClient client = new OkHttpClient();
+ private final Request.Builder builder = new Request.Builder();
+ private final OkHttpClient client = new OkHttpClient.Builder()
+ .readTimeout(30, TimeUnit.SECONDS)
+ .connectTimeout(30, TimeUnit.SECONDS)
+ .writeTimeout(30, TimeUnit.SECONDS)
+ .build(); //设置各种超时时间
+
+ /**
+ @param isAddXuexinHeader 是否加入学信网header到请求头
+ */
+ public HttpReq(boolean isAddXuexinHeader){
+ if (isAddXuexinHeader == true){
+ builder.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
+ builder.addHeader("Accept-Encoding","gzip, deflate, sdch, br");
+ builder.addHeader("Accept-Language","zh-CN,zh;q=0.8");
+ builder.addHeader("Cache-Control","max-age=0");
+ builder.addHeader("Connection","keep-alive");
+ builder.addHeader("Host","my.chsi.com.cn");
+ builder.addHeader("If-Modified-Since","Tue, 13 Mar 2018 10:14:31 GMT");
+ builder.addHeader("Upgrade-Insecure-Requests","1");
+ builder.addHeader( "User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36");
+ }
+ }
+
+ /**
+ @param cookie 加入cookie到请求头
+ */
+ public void addCookieToHeader(String cookie){
+ builder.addHeader("cookie",cookie);
+ }
+
+ /**
+ @param url get请求的url
+ */
+ public String get(String url) {
+ builder.url(url);
+ final Request request = builder.build();
+ try (Response response = client.newCall(request).execute()) {
+ return response.body().string();
+ }catch (Exception e){
+ e.printStackTrace();
+ return "";
+ }
+ }
+
+ /**
+ @param url 图片的地址
+ * */
+ public void savePicture(String url) {
+ builder.url(url);
+ final Request request = builder.build();
+ try (Response response = client.newCall(request).execute()) {
+ byte[] bt = response.body().bytes();
+ byte2image(bt, "./xueji.png");
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ }
+
+ private void byte2image(byte[] data,String path){
+ try {
+ File file = new File(path);
+ FileOutputStream fos = new FileOutputStream(file);
+ fos.write(data, 0, data.length);
+ fos.flush();
+ fos.close();
+ System.out.println("保存图片成功。。");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ public static void testBaidu(){
+ HttpReq baiduHttp = new HttpReq(false);
+ String respStr = baiduHttp.get("http://www.baidu.com");
+ System.out.println(respStr);
+ }
+
+ public static void main(String[] args) {
+ // testBaidu();
+// HttpReq xuexinHttp = new HttpReq(true);
+// xuexinHttp.addCookieToHeader("aliyungf_tc=a44cd76725072e97c6625bc216dcf07870bb8f59efdab8e85142cd2903f45841; acw_tc=707c9f7216885291604143483e1ffdbde1d42ca14b99ec2b9ec8d2c48e0eb1; JSESSIONID=92648EE2F4820DEDD6FB627E7F9DFABE; CHSICC_CLIENTFLAGCHSI=d6d1556d12784a270db64720aa7652f7; goaYXsyEWlxdO=60.I6m8rZy8fEGYpPmjsxJzcQD7H_fstonBF3XyGvvyhDh1_7c_JIFFrAfHsmKk6KtOVWbM2ztenFjMrPRSWIm1a; Hm_lvt_9c8767bf2ffaff9d16e0e409bd28017b=1688529126; zg_did=%7B%22did%22%3A%20%22189242dc17d992-0d47d539a4c70c-3d267449-144000-189242dc17e9f3%22%7D; _gid=GA1.3.678250233.1688529126; CHSICC01=!bLuJc+pYd0Ah1bvzYxYLahOzddj6Y5Wo66QcNq34LuAZUVPejROt5X6Oa37p4b53SrFxCblP8+yMsQ==; zg_14e129856fe4458eb91a735923550aa6=%7B%22sid%22%3A%201688529125761%2C%22updated%22%3A%201688529387258%2C%22info%22%3A%201688529125764%2C%22superProperty%22%3A%20%22%7B%7D%22%2C%22platform%22%3A%20%22%7B%7D%22%2C%22utm%22%3A%20%22%7B%7D%22%2C%22referrerDomain%22%3A%20%22%22%7D; Hm_lpvt_9c8767bf2ffaff9d16e0e409bd28017b=1688529387; _gat_gtag_UA_100524_1=1; _ga_8YMQD1TE48=GS1.1.1688529126.1.1.1688529387.0.0.0; _ga=GA1.1.2127309674.1688529126; goaYXsyEWlxdP=0jBX.aMEoAQAFi9Gmc9MppqIgDOlO8y_aQsmwyuvCdpbPOREblHy3rBYZ3akqvFSvw4wcAomCzMD_pFYl8MVkZ2D23rBjUNOxrqv.5iDjY66XvY1Pna6naF2xfKgvnvDTi5eOmrfSMgXiCW0EXcoGodkTJzbf6zmAqNcyw9aqpiBX980BsYj_Cgp5dDZvXxPK6yti7dHIQ_Oc7fWCOHPmjc7fRt.Xb0WxDqaQ7nQHckj9in8oSZf6uK6M5cjzp804QvVOiUoBq07KdCj_jVLIJndVclyF8iiT5Y5ytnCRogjhcgk_iGonLzXlugXQ7gfCbLlgqtmvJCIkhX99I0PwWYJ_Y5xuQuDhUM7kfwqBJSxm6MrozS7XHgvpKxTtg7pwg07awfezZWbh4ZCNidpXf5E90ppv4hFizfKH7ZUgQ0a"); //由webview执行js返回。
+// xuexinHttp.savePicture("https://www.chsi.com.cn/xlcx/bg.do?vcode=AA33TE9X16WA202D&srcid=bgcx"); //由webview执行js返回。
+ String s = HttpUtil.get("https://www.chsi.com.cn/xlcx/bg.do?vcode=AA33TE9X16WA202D&srcid=bgcx");
+ parseXueJi(s);
+
+ }
+
+ /**
+ * 学籍解析
+ */
+ private static void parseXueJi(String strHtml) {
+ Document doc = Jsoup.parse(strHtml, "UTF-8");
+ Elements eleDiv2 = doc.getElementsByClass("report-info");
+ if (eleDiv2 != null && !eleDiv2.isEmpty()) {
+ Elements eleTd = eleDiv2.get(0).getElementsByTag("div");
+ String text = eleTd.get(4).text();
+ /* if (eleTd != null && !eleTd.isEmpty()) {
+ StuInfo stuInfo = new StuInfo();
+ // 姓名是图片,调用腾讯API实现ocr识别
+ String nameImg = eleTd.get(1).getElementsByTag("img").get(0).attr("src");
+ stuInfo.setName(aiOcr(nameImg));
+ stuInfo.setGender(eleTd.get(4).text());
+ stuInfo.setIdCard(eleTd.get(6).text());
+ stuInfo.setNation(eleTd.get(8).text());
+ stuInfo.setBirthDay(eleTd.get(10).text());
+ stuInfo.setUniversity(eleTd.get(12).text());
+ stuInfo.setLevel(eleTd.get(14).text());
+ stuInfo.setDepartment(eleTd.get(16).text());
+ stuInfo.setSClass(eleTd.get(18).text());
+ stuInfo.setDomain(eleTd.get(20).text());
+ stuInfo.setStuNum(eleTd.get(22).text());
+ stuInfo.setForm(eleTd.get(24).text());
+ stuInfo.setEntranceDate(eleTd.get(26).text());
+ stuInfo.setLenOfSchooling(eleTd.get(28).text());
+ stuInfo.setType(eleTd.get(30).text());
+ String[] status = eleTd.get(32).text().split("\\(");
+ stuInfo.setStatus(status[0]);
+ stuInfo.setGraduationDate(status[1].substring(0, status[1].length() - 1));*/
+// return stuInfo;
+// }
+ }
+// return null;
+ }
+
+ /**
+ * 学历解析
+ */
+ /*private static StuInfo parseXueLi(String strHtml) {
+ Document doc = Jsoup.parse(strHtml, "UTF-8");
+ Elements eleDiv2 = doc.getElementsByClass("div2");
+ if (eleDiv2 != null && !eleDiv2.isEmpty()) {
+ Elements eleTd = eleDiv2.get(0).getElementsByTag("td");
+ if (eleTd != null && !eleTd.isEmpty()) {
+ StuInfo stuInfo = new StuInfo();
+ // 姓名是图片,调用腾讯API实现ocr识别
+ String nameImg = eleTd.get(0).getElementsByTag("img").get(0).attr("src");
+ stuInfo.setName(aiOcr(nameImg));
+ stuInfo.setGender(eleTd.get(2).text());
+ stuInfo.setBirthDay(eleTd.get(3).text());
+ stuInfo.setEntranceDate(eleTd.get(4).text());
+ stuInfo.setGraduationDate(eleTd.get(5).text());
+ stuInfo.setType(eleTd.get(6).text());
+ stuInfo.setLevel(eleTd.get(7).text());
+ stuInfo.setUniversity(eleTd.get(8).text());
+ stuInfo.setLenOfSchooling(eleTd.get(9).text());
+ stuInfo.setDomain(eleTd.get(10).text());
+ stuInfo.setForm(eleTd.get(11).text());
+ stuInfo.setCertificateNum(eleTd.get(12).text());
+ // 状态是图片,调用腾讯API实现ocr识别
+ String statusImg = eleTd.get(13).getElementsByTag("img").get(0).attr("src");
+ stuInfo.setStatus(aiOcr(statusImg));
+ stuInfo.setPresident(eleTd.get(14).text());
+ return stuInfo;
+ }
+ }
+ return null;
+ }*/
+}
diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index b1ae8c99c..477d9088b 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -165,6 +165,62 @@
ip2region
+
+ commons-fileupload
+ commons-fileupload
+
+
+
+ commons-io
+ commons-io
+ 2.11.0
+
+
+
+
+ com.deepoove
+ poi-tl
+ 1.12.1
+
+
+
+
+ com.antherd
+ sm-crypto
+ 0.3.2
+
+
+
+
+ org.jsoup
+ jsoup
+ 1.15.4
+
+
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/advice/DecodeRequestBodyAdvice.java b/ruoyi-common/src/main/java/com/ruoyi/common/advice/DecodeRequestBodyAdvice.java
new file mode 100644
index 000000000..4c26b5bc5
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/advice/DecodeRequestBodyAdvice.java
@@ -0,0 +1,151 @@
+package com.ruoyi.common.advice;
+
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.http.useragent.Platform;
+import cn.hutool.http.useragent.UserAgent;
+import cn.hutool.http.useragent.UserAgentUtil;
+import com.ruoyi.common.core.domain.RsaSecurity;
+import com.ruoyi.common.core.service.ConfigService;
+import com.ruoyi.common.core.service.IRsaSecurityService2;
+import com.ruoyi.common.utils.RSAUtil;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.spring.SpringUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Type;
+import java.rmi.ServerException;
+import java.util.List;
+
+/**
+ * @author monkey
+ * @desc 请求数据解密
+ * @date 2018/10/29 20:17
+ */
+@ControllerAdvice
+public class DecodeRequestBodyAdvice implements RequestBodyAdvice {
+
+ private static final Logger logger = LoggerFactory.getLogger(DecodeRequestBodyAdvice.class);
+ private static final IRsaSecurityService2 rsaSecurityService= SpringUtils.getBean(IRsaSecurityService2.class);
+
+ @Override
+ public boolean supports(MethodParameter methodParameter, Type type, Class extends HttpMessageConverter>> aClass) {
+ return true;
+ }
+
+ @Override
+ public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class extends HttpMessageConverter>> aClass) {
+ return body;
+ }
+
+ @Override
+ public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type type, Class extends HttpMessageConverter>> aClass) throws IOException {
+ try {
+ String path = inputMessage.getHeaders().getFirst("path");
+ String method = inputMessage.getHeaders().getFirst("method");
+ if (ObjectUtil.isNotNull(path)) {
+ RsaSecurity info = rsaSecurityService.getInfo(path, StringUtils.toRootUpperCase(method));
+ if (ObjectUtil.isNotNull(info)) {
+ if ("1".equals(info.getRestricted())){
+ throw new ServerException("接口已限制请求");
+ }
+ if ("1".equals(info.getInDecode())) {
+ return new RsaHttpInputMessage(inputMessage, info.getPrivateKey());
+ }
+
+ }
+ }
+ /*if (methodParameter.getMethod().isAnnotationPresent(RsaSecurityParameter.class)) {
+ //获取注解配置的包含和去除字段
+ RsaSecurityParameter serializedField = methodParameter.getMethodAnnotation(RsaSecurityParameter.class);
+ //入参是否需要解密
+ if (serializedField.inDecode()) {
+ logger.info("注解RsaSecurityParameter,对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密");
+ return new RsaHttpInputMessage(inputMessage);
+ }
+ }*/
+ return inputMessage;
+ } catch (Exception e) {
+ e.printStackTrace();
+ logger.error("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常:" + e.getMessage());
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ @Override
+ public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class extends HttpMessageConverter>> aClass) {
+ return body;
+ }
+
+ class RsaHttpInputMessage implements HttpInputMessage {
+ private HttpHeaders headers;
+
+ private InputStream body;
+
+ public RsaHttpInputMessage(HttpInputMessage inputMessage,String privateKey ) throws Exception {
+ this.headers = inputMessage.getHeaders();
+ String targe="pc";
+ List list = headers.get("targe");
+ if (ObjectUtil.isNotNull(list) && list.size()>0) {
+ boolean wxixin = list.contains("weixin");
+ if (wxixin) {
+ targe = "weixin";
+ }
+ }
+ this.body = IoUtil.toUtf8Stream(easpString(IoUtil.readUtf8(inputMessage.getBody()),targe,privateKey));
+ }
+
+ @Override
+ public InputStream getBody() {
+ return body;
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ return headers;
+ }
+
+ public String easpString(String requestData,String targe,String privateKey) throws IOException {
+ if (requestData != null && !requestData.equals("")) {
+ if (StringUtils.isEmpty(requestData)) {
+ throw new RuntimeException("参数【requestData】缺失异常!");
+ } else {
+ String content = null;
+ try {
+ logger.info("解密密文:"+requestData);
+ String substring1 = StringUtils.substring(requestData, 0, 1);
+ if ("\"".equals(substring1)){
+ String data1 = requestData.substring(1);
+ String substring = requestData.substring(1, data1.length());
+ content = RSAUtil.privateKeyDecryptStr(substring,privateKey);
+ }else {
+ content = RSAUtil.privateKeyDecryptStr(requestData,privateKey);
+ }
+ logger.info("解密明文:"+content);
+ } catch (Exception e) {
+ throw new RuntimeException("msg:参数【aseKey】解析异常!");
+ }
+ try {
+ } catch (Exception e) {
+ throw new ServerException("msg:参数【content】解析异常!");
+ }
+ if (StringUtils.isEmpty(content)) {
+ throw new RuntimeException("msg:参数【requestData】解析参数空指针异常!");
+ }
+ return content;
+ }
+ }
+ throw new RuntimeException("msg:参数【requestData】不合法异常!");
+ }
+ }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/advice/EncodeResponseBodyAdvice.java b/ruoyi-common/src/main/java/com/ruoyi/common/advice/EncodeResponseBodyAdvice.java
new file mode 100644
index 000000000..210ba539e
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/advice/EncodeResponseBodyAdvice.java
@@ -0,0 +1,95 @@
+package com.ruoyi.common.advice;
+import cn.hutool.core.util.ObjectUtil;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.domain.RsaSecurity;
+import com.ruoyi.common.core.service.IRsaSecurityService2;
+import com.ruoyi.common.utils.JsonUtils;
+import com.ruoyi.common.utils.RSAUtil;
+import com.ruoyi.common.utils.spring.SpringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.MediaType;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+/**
+ * @author monkey
+ * @desc 返回数据加密
+ * @date 2018/10/25 20:17
+ */
+@ControllerAdvice
+public class EncodeResponseBodyAdvice implements ResponseBodyAdvice {
+ private final static Logger logger = LoggerFactory.getLogger(EncodeResponseBodyAdvice.class);
+ private static final IRsaSecurityService2 rsaSecurityService=SpringUtils.getBean(IRsaSecurityService2.class);
+
+
+ @Override
+ public boolean supports(MethodParameter methodParameter, Class aClass) {
+ return true;
+ }
+
+ @Override
+ public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
+ // 此处要用反射将字段中的注解解析出来
+ String method = serverHttpRequest.getMethod().name();
+ String path = serverHttpRequest.getURI().getPath();
+ RsaSecurity info = rsaSecurityService.getInfo(path,method);
+ if (ObjectUtil.isNotNull(info)) {
+ if ("1".equals(info.getRestricted())){
+ return R.fail("接口已限制请求");
+ }
+ if ("1".equals(info.getOutEncode())) {
+ serverHttpResponse.getHeaders().add("isRsaencrypt","true");
+ return encodeRsa(methodParameter, body, info.getPublicKey());
+ }
+ }
+ serverHttpResponse.getHeaders().add("isRsaencrypt","false");
+ return body;
+ /*if (methodParameter.getMethod().isAnnotationPresent(RsaSecurityParameter.class)) {
+ //获取注解配置的包含和去除字段
+ RsaSecurityParameter serializedField = methodParameter.getMethodAnnotation(RsaSecurityParameter.class);
+ //出参是否需要加密
+ if (serializedField.outEncode()) {
+ return encodeRsa(methodParameter, body,serializedField.outPublicKey());
+ }
+ }
+ JSONObject jsonObject = JSONUtil.parseObj(body);
+ Object code = jsonObject.get("code");
+ String num = "500";
+ String num2 ="401";
+ String num3 ="403";
+ if (ObjectUtil.isNotNull(code)){
+ if (num.equals(code.toString()) || num2.equals(code.toString()) || num3.equals(code.toString())){
+ return encodeRsa(methodParameter, body,"");
+ }
+ }
+ return body;*/
+ }
+
+ /**
+ * RSA私钥加密
+ *
+ * @param methodParameter
+ * @param body
+ * @return
+ */
+ private Object encodeRsa(MethodParameter methodParameter, Object body,String outPublicKey) {
+ try {
+ String result = JsonUtils.toJsonString(body);
+ logger.info("对返回数据 :【" + result + "】进行加密");
+ String s = RSAUtil.publicKeyEncryptBase64(result,outPublicKey);
+ logger.info("加密之后密文:"+s);
+ return s;
+ } catch (Exception e) {
+ e.printStackTrace();
+ logger.error("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行加密出现异常:" + e.getMessage());
+ }
+ return body;
+ }
+}
+
+
+
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
index 0fb2c3f97..d3ae94864 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
@@ -41,4 +41,20 @@ public interface CacheConstants {
* 登录账户密码错误次数 redis key
*/
String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
+
+
+ /**
+ * 注册发送验证码
+ */
+ String REGISTER_SEND_MSG = "register_send_msg:";
+
+ /**
+ * 忘记密码发送验证码
+ */
+ String RORGOT_PASSWORD_SEND_MSG = "rorgot_password_send_msg:";
+
+ /**
+ * 短信登录发送验证码
+ */
+ String SMS_LOGIN_SEND_MSG = "sms_login_send_msg:";
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheNames.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheNames.java
index 1396b6d18..ed249987c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheNames.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheNames.java
@@ -30,6 +30,9 @@ public interface CacheNames {
*/
String SYS_DICT = "sys_dict";
+
+ String RSA_SECURITY = "rsa_security";
+
/**
* 用户账户
*/
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
index e634ed297..cbaff1d45 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
@@ -72,5 +72,46 @@ public interface Constants {
*/
String TOKEN = "token";
+ /**
+ * 待提交
+ */
+ String SUBMIT = "0";
+
+ /**
+ * 审核等待中
+ */
+ String WAIT = "1";
+
+ /**
+ * 审核失败
+ */
+ String FAILD = "2";
+
+
+ /**
+ * 公式中
+ */
+ String PUBLICS = "3";
+
+ /**
+ * 公式失败
+ */
+ String PUBLICSFail = "4";
+
+ /**
+ * 审核成功
+ */
+ String SUCCEED = "5";
+
+ /**
+ * 取消资格
+ */
+ String CANCEL = "6";
+
+ /**
+ * 数据不存在
+ */
+ String NONENTITY = "nonentity";
+
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
index 569c5dafa..6c01ae842 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
@@ -121,8 +121,9 @@ public interface UserConstants {
/**
* 密码长度限制
*/
- int PASSWORD_MIN_LENGTH = 5;
+ int PASSWORD_MIN_LENGTH = 8;
int PASSWORD_MAX_LENGTH = 20;
+ String PASSWORD_Pattern = "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,18}$";
/**
* 管理员ID
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
index bd316079a..6a66d1b0a 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
@@ -2,6 +2,7 @@ package com.ruoyi.common.core.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
@@ -39,6 +40,7 @@ public class BaseEntity implements Serializable {
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date createTime;
/**
@@ -51,6 +53,7 @@ public class BaseEntity implements Serializable {
* 更新时间
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date updateTime;
/**
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java
index 381a6f602..343d55aec 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java
@@ -47,6 +47,9 @@ public class R implements Serializable {
public static R ok(String msg, T data) {
return restResult(data, SUCCESS, msg);
}
+ public static R ok(int code,String msg, T data) {
+ return restResult(data, code, msg);
+ }
public static R fail() {
return restResult(null, FAIL, "操作失败");
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/RsaSecurity.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/RsaSecurity.java
new file mode 100644
index 000000000..0e33a0e2d
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/RsaSecurity.java
@@ -0,0 +1,61 @@
+package com.ruoyi.common.core.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.io.Serializable;
+import java.util.Date;
+import java.math.BigDecimal;
+
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 请求RSA数据加解密对象 rsa_security
+ *
+ * @author ruoyi
+ * @date 2023-05-17
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("rsa_security")
+public class RsaSecurity extends BaseEntity {
+
+ private static final long serialVersionUID=1L;
+
+ /**
+ *
+ */
+ @TableId(value = "id",type = IdType.AUTO)
+ private Long id;
+ /**
+ * 需要加密的接口
+ */
+ private String path;
+ /**
+ * 入参是否解密,默认不解密
+ */
+ private String inDecode;
+ /**
+ * 出参是否加密,默认加密
+ */
+ private String outEncode;
+ /**
+ * 公钥
+ */
+ private String publicKey;
+ /**
+ * 私钥
+ */
+ private String privateKey;
+
+ /**
+ * 请求方式
+ */
+ private String method;
+
+ /**
+ * 接口限制请求
+ */
+ private String restricted;
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/GaoXinCardInfo.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/GaoXinCardInfo.java
new file mode 100644
index 000000000..cdc77614b
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/GaoXinCardInfo.java
@@ -0,0 +1,85 @@
+package com.ruoyi.common.core.domain.entity;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.ruoyi.common.exception.ServiceException;
+import lombok.Data;
+import org.springframework.util.StringUtils;
+
+import java.io.Serializable;
+
+/**
+ * @author Administrator
+ * 高新人才接口返回所需
+ */
+
+@Data
+public class GaoXinCardInfo implements Serializable {
+
+ /**
+ * 身份证
+ */
+ private String card_id;
+ /**
+ * 国籍
+ */
+ private String nationality;
+ /**
+ * 姓名
+ */
+ private String name;
+ /**
+ * 手机号
+ */
+ private String phone;
+ /**
+ * 公司名称
+ */
+ private String company_name;
+ /**
+ * 性别
+ */
+ private String sex;
+ /**
+ * 公司所在区域
+ */
+ private String district;
+ /**
+ * 人才类型
+ */
+ private String type;
+ /**
+ * 学历
+ */
+ private String education;
+
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ if (ObjectUtil.isNotNull(type) && ObjectUtil.isNotEmpty(type)) {
+ type = StringUtils.trimAllWhitespace(type);
+ if (type.length() == 1) {
+ this.type = type + "类";
+ }else {
+ this.type = type;
+ }
+ }
+ }
+
+ public String getNationality() {
+ return nationality;
+ }
+
+ public void setNationality(String nationality) {
+ if (ObjectUtil.isNotNull(nationality) && ObjectUtil.isNotEmpty(nationality)) {
+ nationality = StringUtils.trimAllWhitespace(nationality);
+ if ("中国".equals(nationality)) {
+ this.nationality = nationality + "籍";
+ }else {
+ this.nationality = nationality;
+ }
+ }
+ }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/StuInfo.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/StuInfo.java
new file mode 100644
index 000000000..ae5fba34c
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/StuInfo.java
@@ -0,0 +1,95 @@
+package com.ruoyi.common.core.domain.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class StuInfo implements Serializable {
+
+ /**
+ * 头像
+ */
+ private String headImg;
+
+ /**
+ * 姓名
+ */
+ private String userName;
+
+ /**
+ * 性别
+ */
+ private String sex;
+
+ /**
+ * 证件号码
+ */
+ private String idCard;
+ /**
+ * 民族
+ */
+ private String nation;
+ /**
+ * 出生日期
+ */
+ private String birthDay;
+ /**
+ * 院校
+ */
+ private String university;
+ /**
+ * 院系
+ */
+ private String department;
+ /**
+ * 专业
+ */
+ private String domain;
+ /**
+ * 层次,如本科
+ */
+ private String level;
+ /**
+ * 班级
+ */
+ private String sClass;
+ /**
+ * 学号
+ */
+ private String stuNum;
+ /**
+ * 形式
+ */
+ private String form;
+ /**
+ * 入学时间
+ */
+ private String entranceDate;
+ /**
+ * 学制
+ */
+ private String lenOfSchooling;
+ /**
+ * 类型
+ */
+ private String type;
+ /**
+ * 学籍状态
+ */
+ private String status;
+ /**
+ * 毕业时间
+ */
+ private String graduationDate;
+ /**
+ * 学历证书编号
+ */
+ private String certificateNum;
+ /**
+ * 校长
+ */
+ private String president;
+
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
index ba4a382c7..99ee336be 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
@@ -1,5 +1,6 @@
package com.ruoyi.common.core.domain.entity;
+import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -27,7 +28,7 @@ public class SysDept extends TreeEntity {
/**
* 部门ID
*/
- @TableId(value = "dept_id")
+ @TableId(value = "dept_id",type = IdType.AUTO)
private Long deptId;
/**
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
index 4ed2c5483..e050740e4 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
@@ -2,6 +2,7 @@ package com.ruoyi.common.core.domain.entity;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
+import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.annotation.ExcelDictFormat;
@@ -30,7 +31,7 @@ public class SysDictData extends BaseEntity {
* 字典编码
*/
@ExcelProperty(value = "字典编码")
- @TableId(value = "dict_code")
+ @TableId(value = "dict_code",type = IdType.AUTO)
private Long dictCode;
/**
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
index 76c20e102..035757cfa 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
@@ -2,6 +2,7 @@ package com.ruoyi.common.core.domain.entity;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
+import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.annotation.ExcelDictFormat;
@@ -30,7 +31,7 @@ public class SysDictType extends BaseEntity {
* 字典主键
*/
@ExcelProperty(value = "字典主键")
- @TableId(value = "dict_id")
+ @TableId(value = "dict_id",type = IdType.AUTO)
private Long dictId;
/**
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
index 38bd93659..c29373406 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
@@ -1,5 +1,6 @@
package com.ruoyi.common.core.domain.entity;
+import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonInclude;
@@ -25,7 +26,7 @@ public class SysMenu extends TreeEntity {
/**
* 菜单ID
*/
- @TableId(value = "menu_id")
+ @TableId(value = "menu_id",type = IdType.AUTO)
private Long menuId;
/**
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
index 594956998..8d2b34137 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
@@ -2,10 +2,7 @@ package com.ruoyi.common.core.domain.entity;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableLogic;
-import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.*;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.convert.ExcelDictConvert;
@@ -35,7 +32,7 @@ public class SysRole extends BaseEntity {
* 角色ID
*/
@ExcelProperty(value = "角色序号")
- @TableId(value = "role_id")
+ @TableId(value = "role_id",type = IdType.AUTO)
private Long roleId;
/**
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
index 3196e9ecf..f16acc237 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
@@ -33,7 +33,7 @@ public class SysUser extends BaseEntity {
/**
* 用户ID
*/
- @TableId(value = "user_id")
+ @TableId(value = "user_id",type = IdType.AUTO)
private Long userId;
/**
@@ -128,6 +128,11 @@ public class SysUser extends BaseEntity {
*/
private String remark;
+ /**
+ * 楼盘
+ */
+ private String properties;
+
/**
* 部门对象
*/
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/event/PushLogEvent.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/event/PushLogEvent.java
new file mode 100644
index 000000000..2552c8fb1
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/event/PushLogEvent.java
@@ -0,0 +1,37 @@
+package com.ruoyi.common.core.domain.event;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ruoyi.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 推送日志对象 push_log
+ *
+ * @author ruoyi
+ * @date 2023-07-20
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("push_log")
+public class PushLogEvent extends BaseEntity {
+
+ private static final long serialVersionUID=1L;
+
+ /**
+ *
+ */
+ @TableId(value = "id",type = IdType.AUTO)
+ private Long id;
+ /**
+ * 推送数据
+ */
+ private String pushData;
+ /**
+ * 返回结果
+ */
+ private String resultData;
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java
index 4a4cfb518..21bc4dff4 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java
@@ -5,6 +5,7 @@ import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
/**
* 用户登录对象
@@ -18,20 +19,22 @@ public class LoginBody {
/**
* 用户名
*/
- @NotBlank(message = "{user.username.not.blank}")
- @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}")
+ @NotBlank(message = "{user.username.not.blank}",groups = {passwordLogin.class,smgLogin.class,forgetPasswordLogin.class,registerUser.class,userOpenLogin.class})
+ @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}",groups = {passwordLogin.class,smgLogin.class,forgetPasswordLogin.class,registerUser.class})
private String username;
/**
* 用户密码
*/
- @NotBlank(message = "{user.password.not.blank}")
- @Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}")
+ @NotBlank(message = "{user.password.not.blank}",groups = {passwordLogin.class,forgetPasswordLogin.class,registerUser.class})
+ @Pattern(regexp = UserConstants.PASSWORD_Pattern,message = "{the.password.is.not.within.the.specified.range}",groups = {passwordLogin.class,forgetPasswordLogin.class,registerUser.class})
+ @Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}",groups = {passwordLogin.class,forgetPasswordLogin.class,registerUser.class})
private String password;
/**
* 验证码
*/
+ @NotBlank(message = "{user.jcaptcha.not.blank}",groups = {smgLogin.class,forgetPasswordLogin.class,registerUser.class})
private String code;
/**
@@ -39,4 +42,37 @@ public class LoginBody {
*/
private String uuid;
+
+ /**
+ * 外部用户标识key
+ */
+ @NotBlank(message = "user.id.cannot.be.empty",groups ={userOpenLogin.class})
+ private String apiKey;
+
+
+ /**
+ * 账号登录验证
+ */
+ public interface passwordLogin {}
+
+ /**
+ * 短信登录验证
+ */
+ public interface smgLogin {}
+
+ /**
+ * 忘记密码验证
+ */
+ public interface forgetPasswordLogin {}
+
+ /**
+ * 注册验证
+ */
+ public interface registerUser {}
+
+ public interface userOpenLogin {}
+
+
+
}
+
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
index 83fcf9fe8..09258d8e5 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
@@ -90,6 +90,17 @@ public class LoginUser implements Serializable {
*/
private String username;
+ private String nickName;
+
+ private String companyId;
+
+ /**
+ * 楼盘
+ */
+ private String properties;
+
+
+
/**
* 角色对象
*/
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/SmsLoginBody.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/SmsLoginBody.java
index b12e74c14..0477a1d57 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/SmsLoginBody.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/SmsLoginBody.java
@@ -17,12 +17,12 @@ public class SmsLoginBody {
* 手机号
*/
@NotBlank(message = "{user.phonenumber.not.blank}")
- private String phonenumber;
+ private String username;
/**
* 短信code
*/
@NotBlank(message = "{sms.code.not.blank}")
- private String smsCode;
+ private String verificationCode;
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/UserLoginBody.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/UserLoginBody.java
new file mode 100644
index 000000000..5a40662ca
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/UserLoginBody.java
@@ -0,0 +1,45 @@
+package com.ruoyi.common.core.domain.model;
+
+import com.ruoyi.common.constant.UserConstants;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 用户登录对象
+ *
+ * @author Lion Li
+ */
+
+@Data
+public class UserLoginBody {
+
+ /**
+ * 用户名
+ */
+ @NotBlank(message = "{user.username.not.blank}")
+ @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}")
+ private String username;
+
+ /**
+ * 用户密码
+ */
+ @NotBlank(message = "{user.password.not.blank}")
+ @Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}")
+ private String password;
+
+ /**
+ * 验证码
+ */
+ @NotBlank(message = "{user.code.not.blank}")
+ private String code;
+
+ /**
+ * 唯一标识
+ */
+ @NotBlank(message = "{user.password.not.blank}")
+ @Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}")
+ private String twoPassword;
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/service/ConfigService.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/service/ConfigService.java
index c6badf65c..fa02e268c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/service/ConfigService.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/service/ConfigService.java
@@ -1,5 +1,8 @@
package com.ruoyi.common.core.service;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
/**
* 通用 参数配置服务
*
@@ -15,4 +18,11 @@ public interface ConfigService {
*/
String getConfigValue(String configKey);
+ /**
+ * 根据key获取数据
+ * @param configKey
+ * @return
+ */
+ void selectConfigByConfigKey(String configKey);
+
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/service/IRsaSecurityService2.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/service/IRsaSecurityService2.java
new file mode 100644
index 000000000..3141d1399
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/service/IRsaSecurityService2.java
@@ -0,0 +1,9 @@
+package com.ruoyi.common.core.service;
+
+
+import com.ruoyi.common.core.domain.RsaSecurity;
+
+public interface IRsaSecurityService2 {
+
+ RsaSecurity getInfo(String path,String method);
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/validate/DownloadGroup.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/validate/DownloadGroup.java
new file mode 100644
index 000000000..db1a7d4e7
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/validate/DownloadGroup.java
@@ -0,0 +1,4 @@
+package com.ruoyi.common.core.validate;
+
+public interface DownloadGroup {
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
index 897f7068f..1d9783fae 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
@@ -1,24 +1,30 @@
-package com.ruoyi.common.enums;
-
-/**
- * 限流类型
- *
- * @author ruoyi
- */
-
-public enum LimitType {
- /**
- * 默认策略全局限流
- */
- DEFAULT,
-
- /**
- * 根据请求者IP进行限流
- */
- IP,
-
- /**
- * 实例限流(集群多后端实例)
- */
- CLUSTER
-}
+package com.ruoyi.common.enums;
+
+/**
+ * 限流类型
+ *
+ * @author ruoyi
+ */
+
+public enum LimitType {
+ /**
+ * 默认策略全局限流
+ */
+ DEFAULT,
+
+ /**
+ * 根据请求者IP进行限流
+ */
+ IP,
+
+ /**
+ * 用户id
+ */
+ USERID,
+
+
+ /**
+ * 实例限流(集群多后端实例)
+ */
+ CLUSTER
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/LoginType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/LoginType.java
index 875e4762e..c3103b2d5 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/LoginType.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/LoginType.java
@@ -41,4 +41,5 @@ public enum LoginType {
* 登录重试限制计数提示
*/
final String retryLimitCount;
+
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java
new file mode 100644
index 000000000..38ef24856
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java
@@ -0,0 +1,83 @@
+package com.ruoyi.common.exception.file;
+
+import org.apache.commons.fileupload.FileUploadException;
+
+import java.util.Arrays;
+
+/*
+ * 文件上传 误异常类
+ *
+ * @author ruoyi
+ */
+
+public class InvalidExtensionException extends FileUploadException
+{
+ private static final long serialVersionUID = 1L;
+
+ private String[] allowedExtension;
+ private String extension;
+ private String filename;
+
+ public InvalidExtensionException(String[] allowedExtension, String extension, String filename)
+ {
+ super("filename : [" + filename + "], extension : [" + extension + "], allowed extension : [" + Arrays.toString(allowedExtension) + "]");
+ this.allowedExtension = allowedExtension;
+ this.extension = extension;
+ this.filename = filename;
+ }
+
+ public String[] getAllowedExtension()
+ {
+ return allowedExtension;
+ }
+
+ public String getExtension()
+ {
+ return extension;
+ }
+
+ public String getFilename()
+ {
+ return filename;
+ }
+
+ public static class InvalidImageExtensionException extends InvalidExtensionException
+ {
+ private static final long serialVersionUID = 1L;
+
+ public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename)
+ {
+ super(allowedExtension, extension, filename);
+ }
+ }
+
+ public static class InvalidFlashExtensionException extends InvalidExtensionException
+ {
+ private static final long serialVersionUID = 1L;
+
+ public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename)
+ {
+ super(allowedExtension, extension, filename);
+ }
+ }
+
+ public static class InvalidMediaExtensionException extends InvalidExtensionException
+ {
+ private static final long serialVersionUID = 1L;
+
+ public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename)
+ {
+ super(allowedExtension, extension, filename);
+ }
+ }
+
+ public static class InvalidVideoExtensionException extends InvalidExtensionException
+ {
+ private static final long serialVersionUID = 1L;
+
+ public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename)
+ {
+ super(allowedExtension, extension, filename);
+ }
+ }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
index 8927366e0..3e9b8997d 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
@@ -1,11 +1,22 @@
package com.ruoyi.common.filter;
+import cn.hutool.core.util.ObjectUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ruoyi.common.core.service.ConfigService;
import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.spring.SpringUtils;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/**
* Repeatable 过滤器
@@ -13,9 +24,9 @@ import java.io.IOException;
* @author ruoyi
*/
public class RepeatableFilter implements Filter {
+
@Override
public void init(FilterConfig filterConfig) throws ServletException {
-
}
@Override
@@ -23,9 +34,13 @@ public class RepeatableFilter implements Filter {
throws IOException, ServletException {
ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest
- && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
+ && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE) ) {
requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
}
+ if (!isSafe((HttpServletRequest) request,(HttpServletResponse) response)) {
+ ((HttpServletResponse) response).setStatus(403);
+ return;
+ }
if (null == requestWrapper) {
chain.doFilter(request, response);
} else {
@@ -37,4 +52,59 @@ public class RepeatableFilter implements Filter {
public void destroy() {
}
+
+ /**
+ * 判断请求是正确
+ *
+ * @param request
+ * @return
+ */
+ private boolean isSafe(HttpServletRequest request,HttpServletResponse response) {
+ ConfigService sysConfigService = SpringUtils.getBean(ConfigService.class);
+ String configValue = sysConfigService.getConfigValue("sys:preventing:hotlinking");
+ List strings = Arrays.asList(configValue.split(","));
+ if (ObjectUtil.isEmpty(configValue)) {
+ // 未设置任何链接,表示所有来源都可以访问
+ return true;
+ }
+ String referer = request.getHeader("referer");
+ if (referer == null || "".equals(referer)) {
+ // 获取不到防盗链头部信息 -> 拦截
+ System.out.println("referer为空进行拦截");
+ return true;
+ }
+ for (String white : strings) {
+ if (white.contains("*.")) {
+ // 这里处理*.xxx.com,表示xxx.com下的所有二级域名均可访问,所以就截取掉'*.'符号
+ white = white.replace("*.", "");
+ }
+ // 这里就简单的判断referer请求头中的链接是否包含我们白名单中的域名
+ if (referer.contains(white)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 处理相应数据
+ *
+ * @param response
+ */
+ public void handleResponse(HttpServletResponse response) {
+ // 访问链接有问题
+ try {
+ Map resultMsg = new HashMap<>();
+ resultMsg.put("code", String.valueOf(HttpStatus.FORBIDDEN));
+ resultMsg.put("msg", "资源不允许");
+ ObjectMapper objectMapper = new ObjectMapper();
+ String msg = objectMapper.writeValueAsString(resultMsg);
+ response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
+ response.setStatus(403);
+ response.getWriter().write(msg);
+ } catch (IOException e) {
+ System.out.println("防盗链过滤器处理response失败");
+ }
+ }
+
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/CardsUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/CardsUtil.java
new file mode 100644
index 000000000..9704ce182
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/CardsUtil.java
@@ -0,0 +1,199 @@
+package com.ruoyi.common.utils;
+
+import jodd.util.StringUtil;
+
+/**
+ * @Description 各证件卡号校验类
+ * @author longwei
+ * @date 2020/7/23 14:17
+ */
+public class CardsUtil {
+
+ /** 正则表达式:验证身份证 */
+ public static final String REGEX_ID_CARD = "(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|" +
+ "(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)";
+
+ /** 正则表达式:验证户口簿 9位数字 */
+ public static final String REGEX_HUKOU_CARD = "\\d{9}";
+
+ /** 正则表达式:验证护照 数字+字母,共9位 */
+ public static final String REGEX_PASSPORT_CARD = "^([a-zA-z]|[0-9]){9}$";
+
+ /** 正则表达式:验证军官证 汉字+8位数字 */
+ public static final String REGEX_OFFICER_CARD = "^[\\u4E00-\\u9FA5](字第)([0-9a-zA-Z]{4,8})(号?)$";
+
+ /** 正则表达式:验证驾驶证 12位数字 */
+ public static final String REGEX_DRIVE_CARD = "\\d{12}$";
+
+ /** 正则表达式:验证港澳居民通行证 H/M + 10位或8位数字 */
+ public static final String REGEX_HK_CARD = "^[HMhm]{1}([0-9]{10}|[0-9]{8})$";
+
+ /** 正则表达式:验证台湾居民通行证 新版8位或18位数字,旧版10位数字 + 英文字母 */
+ public static final String REGEX_TW_CARD = "^\\d{8}|^[a-zA-Z0-9]{10}|^\\d{18}$";
+
+ /**
+ * 校验身份证
+ *
+ * @param idCardNo 身份证号
+ * @return 校验通过返回true,否则返回false
+ * @by https://blog.csdn.net/u011106915/article/details/76066985
+ */
+ public static boolean isIDCard(String idCardNo) {
+ //校验非空
+ if (StringUtil.isEmpty(idCardNo)) {
+ return false;
+ }
+ //校验长度
+ int idCardLength = idCardNo.length();
+ if (idCardLength != 18 && idCardLength != 15 && idCardLength != 9) {
+ return false;
+ }
+ if (idCardLength==9){
+ return idCardNo.matches(REGEX_PASSPORT_CARD);
+ }
+ // 定义判别用户身份证号的正则表达式(15位或者18位,最后一位可以为字母)
+ //假设18位身份证号码:41000119910101123X 410001 19910101 123X
+ //^开头
+ //[1-9] 第一位1-9中的一个 4
+ //\\d{5} 五位数字 10001(前六位省市县地区)
+ //(18|19|20) 19(现阶段可能取值范围18xx-20xx年)
+ //\\d{2} 91(年份)
+ //((0[1-9])|(10|11|12)) 01(月份)
+ //(([0-2][1-9])|10|20|30|31)01(日期)
+ //\\d{3} 三位数字 123(第十七位奇数代表男,偶数代表女)
+ //[0-9Xx] 0123456789Xx其中的一个 X(第十八位为校验值)
+ //$结尾
+
+ //假设15位身份证号码:410001910101123 410001 910101 123
+ //^开头
+ //[1-9] 第一位1-9中的一个 4
+ //\\d{5} 五位数字 10001(前六位省市县地区)
+ //\\d{2} 91(年份)
+ //((0[1-9])|(10|11|12)) 01(月份)
+ //(([0-2][1-9])|10|20|30|31)01(日期)
+ //\\d{3} 三位数字 123(第十五位奇数代表男,偶数代表女),15位身份证不含X
+ //$结尾
+
+ boolean matches = idCardNo.matches(REGEX_ID_CARD);
+
+ //判断第18位校验值
+ if (matches) {
+
+ //如是15位身份证,不做更多校验,直接返回合法
+ if (idCardLength == 15) {
+ return true;
+ }
+
+ if (idCardLength == 18) {
+ try {
+ char[] charArray = idCardNo.toCharArray();
+ //前十七位加权因子
+ int[] idCardWi = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
+ //这是除以11后,可能产生的11位余数对应的验证码
+ String[] idCardY = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
+ int sum = 0;
+ for (int i = 0; i < idCardWi.length; i++) {
+ int current = Integer.parseInt(String.valueOf(charArray[i]));
+ int count = current * idCardWi[i];
+ sum += count;
+ }
+ char idCardLast = charArray[17];
+ int idCardMod = sum % 11;
+ return idCardY[idCardMod].toUpperCase().equals(String.valueOf(idCardLast).toUpperCase());
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ }
+ return matches;
+ }
+
+ /**
+ * 校验户口簿
+ *
+ * @param huKouNo 户口簿号
+ * @return 校验通过返回true,否则返回false
+ */
+ public static boolean isHuKouCard(String huKouNo) {
+ //校验非空 校验长度
+ if (StringUtils.isEmpty(huKouNo) || huKouNo.length() != 9 ) {
+ return false;
+ }
+ return huKouNo.matches(REGEX_HUKOU_CARD);
+ }
+
+ /**
+ * 校验护照
+ *
+ * @param passPortNo 护照号
+ * @return 校验通过返回true,否则返回false
+ */
+ public static boolean isPassPortCard(String passPortNo) {
+ //校验非空
+ if (StringUtil.isEmpty(passPortNo)) {
+ return false;
+ }
+ return passPortNo.matches(REGEX_PASSPORT_CARD);
+ }
+
+ /**
+ * 校验军官证
+ * 规则: 军/兵/士/文/职/广/(其他中文) + "字第" + 4到8位字母或数字 + "号"
+ * 样本: 军字第2001988号, 士字第P011816X号
+ * @param officerNo 军官证号
+ * @return 校验通过返回true,否则返回false
+ */
+ public static boolean isofficerCard(String officerNo) {
+ //校验非空
+ if (StringUtil.isEmpty(officerNo)) {
+ return false;
+ }
+ return officerNo.matches(REGEX_OFFICER_CARD);
+ }
+
+ /**
+ * 校验驾驶证
+ *
+ * @param driveNo 驾驶证号
+ * @return 校验通过返回true,否则返回false
+ */
+ public static boolean isDriveCard(String driveNo) {
+ //校验非空 校验长度
+ if (StringUtil.isEmpty(driveNo) || driveNo.length() != 12 ) {
+ return false;
+ }
+ return driveNo.matches(REGEX_DRIVE_CARD);
+ }
+
+ /**
+ * 校验港澳通行证
+ *
+ * @param HMNo 港澳通行证号
+ * @return 校验通过返回true,否则返回false
+ */
+ public static boolean isHMCard(String HMNo) {
+ //校验非空
+ if (StringUtil.isEmpty(HMNo)) {
+ return false;
+ }
+ return HMNo.matches(REGEX_HK_CARD);
+ }
+
+ /**
+ * 校验台湾通行证
+ * 规则 新版8位或18位数字,旧版10位数字 + 英文字母
+ * @param TWNo 台湾通行证号
+ * @return 校验通过返回true,否则返回false
+ */
+ public static boolean isTWCard(String TWNo) {
+ //校验非空
+ if (StringUtil.isEmpty(TWNo)) {
+ return false;
+ }
+ return TWNo.matches(REGEX_TW_CARD);
+ }
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateHolidayUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateHolidayUtils.java
new file mode 100644
index 000000000..db7547a9f
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateHolidayUtils.java
@@ -0,0 +1,769 @@
+package com.ruoyi.common.utils;
+
+import java.math.BigDecimal;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+/**
+ * @Description 时间日期工具类 封装工作中常用的一些时间日期计算方法等,还可以提供更多的重载方法,用于时间的转化等
+ * @author
+ * @Date
+ */
+public class DateHolidayUtils {
+ private DateHolidayUtils() {
+
+ }
+
+ /**
+ * hhmmFormat="HH:mm"
+ */
+ public static final String hhmmFormat = "HH:mm";
+ /**
+ * MMddFormat="MM-dd"
+ */
+ public static final String MMddFormat = "MM-dd";
+ /**
+ * yyyyFormat="yyyy"
+ */
+ public static final String yyyyFormat = "yyyy";
+ /**
+ * yyyyFormat="yyyy-MM"
+ */
+ public static final String yyyyMMFormat = "yyyy-MM";
+ /**
+ * yyyyChineseFormat="yyyy年"
+ */
+ public static final String yyyyChineseFormat = "yyyy年";
+ /**
+ * yyyyMMddFormat="yyyy-MM-dd"
+ */
+ public static final String yyyyMMddFormat = "yyyy-MM-dd";
+ /**
+ * fullFormat="yyyy-MM-dd HH:mm:ss"
+ */
+ public static final String fullFormat = "yyyy-MM-dd HH:mm:ss";
+ /**
+ * yyyyMMddHHmmss="yyyyMMddHHmmss"
+ */
+ public static final String yyyyMMddHHmmss = "yyyyMMddHHmmss";
+ /**
+ * strFormat="yyyy/MM/dd HH:mm:ss"
+ */
+ public static final String strFormat = "yyyy/MM/dd HH:mm:ss";
+ /**
+ * MMddChineseFormat="MM月dd日"
+ */
+ public static final String MMddChineseFormat = "MM月dd日";
+ /**
+ * yyyyMMddChineseFormat="yyyy年MM月dd日"
+ */
+ public static final String yyyyMMddChineseFormat = "yyyy年MM月dd日";
+ /**
+ * yyyyMMddChineseFormat="yyyy年MM月"
+ */
+ public static final String yyyyMMChineseFormat = "yyyy年MM月";
+ /**
+ * fullChineseFormat="yyyy年MM月dd日HH时mm分ss秒"
+ */
+ public static final String fullChineseFormat = "yyyy年MM月dd日HH时mm分ss秒";
+ /**
+ * WEEKS={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"}
+ */
+ public static final String[] WEEKS = { "星期日", "星期一", "星期二", "星期三", "星期四",
+ "星期五", "星期六" };
+
+ /**
+ * 得到指定时间的时间日期格式
+ *
+ * @param date
+ * 指定的时间
+ * @param format
+ * 时间日期格式
+ * @return
+ */
+ public static String getFormatDateTime(Date date, String format) {
+ if(date == null){return "";}
+ DateFormat df = new SimpleDateFormat(format);
+ return df.format(date);
+ }
+ /**
+ * 得到指定时间的时间日期格式(返回date)
+ *
+ * @param date
+ * 指定的时间
+ * @param format
+ * 时间日期格式
+ * @return
+ */
+ public static Date getDateFormatDateTime(Date date, String format) {
+ DateFormat df = new SimpleDateFormat(format);
+ String s=df.format(date);
+ try {
+ return df.parse(s);
+ } catch (ParseException e) { };
+ return date;
+ }
+
+ public static String getFormatDateToday(String format) {
+ return getFormatDateTime(new Date(), format);
+ }
+
+ /**
+ * 判断是否是润年
+ *
+ * @param date
+ * 指定的时间
+ * @return true:是润年,false:不是润年
+ */
+ public static boolean isLeapYear(Date date) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ return isLeapYear(cal.get(Calendar.YEAR));
+ }
+
+ /**
+ * 判断是否是润年
+ *
+ * @param year
+ * 指定的年
+ * @return true:是润年,false:不是润年
+ */
+ public static boolean isLeapYear(int year) {
+ GregorianCalendar calendar = new GregorianCalendar();
+ return calendar.isLeapYear(year);
+ }
+
+ /**
+ * 判断指定的时间是否是今天
+ *
+ * @param date
+ * 指定的时间
+ * @return true:是今天,false:非今天
+ */
+ public static boolean isInToday(Date date) {
+ boolean flag = false;
+ Date now = new Date();
+ String fullFormat = getFormatDateTime(now, DateHolidayUtils.yyyyMMddFormat);
+ String beginString = fullFormat + " 00:00:00";
+ String endString = fullFormat + " 23:59:59";
+ DateFormat df = new SimpleDateFormat(DateHolidayUtils.fullFormat);
+ try {
+ Date beginTime = df.parse(beginString);
+ Date endTime = df.parse(endString);
+ flag = date.before(endTime) && date.after(beginTime);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return flag;
+ }
+
+ /**
+ * 判断两时间是否是同一天
+ *
+ * @param from
+ * 第一个时间点
+ * @param to
+ * 第二个时间点
+ * @return true:是同一天,false:非同一天
+ */
+ public static boolean isSameDay(Date from, Date to) {
+ boolean isSameDay = false;
+ DateFormat df = new SimpleDateFormat(DateHolidayUtils.yyyyMMddFormat);
+ String firstDate = df.format(from);
+ String secondDate = df.format(to);
+ isSameDay = firstDate.equals(secondDate);
+ return isSameDay;
+ }
+
+ /**
+ * 方法描述: 判断两时间是否是同一时间,精确到秒 作者:zhanglei 时间:2013-11-2下午04:22:33
+ *
+ * @param from
+ * 第一个时间点
+ * @param to
+ * 第二个时间点
+ * @return true:是,false:非
+ */
+ public static boolean isSameTime(Date from, Date to) {
+ boolean isSameDay = false;
+ DateFormat df = new SimpleDateFormat(DateHolidayUtils.yyyyMMddHHmmss);
+ String firstDate = df.format(from);
+ String secondDate = df.format(to);
+ isSameDay = firstDate.equals(secondDate);
+ return isSameDay;
+ }
+
+ /**
+ * 求出指定的时间那天是星期几
+ *
+ * @param date
+ * 指定的时间
+ * @return 星期X
+ */
+ public static String getWeekString(Date date) {
+ return DateHolidayUtils.WEEKS[getWeek(date) - 1];
+ }
+
+ /**
+ * 求出指定时间那天是星期几
+ *
+ * @param date
+ * 指定的时间
+ * @return 0-6 分别代表星期日-星期六
+ */
+ public static int getWeekDay(Date date) {
+ int week = getWeek(date);
+ return week-1;
+ }
+
+ /**
+ * 求出指定时间那天是星期几
+ *
+ * @param date
+ * 指定的时间
+ * @return 1-7
+ */
+ public static int getWeek(Date date) {
+ int week = 0;
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ week = cal.get(Calendar.DAY_OF_WEEK);
+ return week;
+ }
+
+ /**
+ * 取得指定时间离现在是多少时间以前,如:3秒前,2小时前等 注意:此计算方法不是精确的
+ *
+ * @param date
+ * 已有的指定时间
+ * @return 时间段描述
+ */
+ public static String getAgoTimeString(Date date) {
+ Date now = new Date();
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ Date agoTime = cal.getTime();
+ long mtime = now.getTime() - agoTime.getTime();
+ String str = "";
+ long stime = mtime / 1000;
+ long minute = 60;
+ long hour = 60 * 60;
+ long day = 24 * 60 * 60;
+ long weeks = 7 * 24 * 60 * 60;
+ long months = 100 * 24 * 60 * 60;
+ if (stime < minute) {
+ long time_value = stime;
+ if (time_value <= 0) {
+ time_value = 1;
+ }
+ str = time_value + "秒前";
+ } else if (stime >= minute && stime < hour) {
+ long time_value = stime / minute;
+ if (time_value <= 0) {
+ time_value = 1;
+ }
+ str = time_value + "分前";
+ } else if (stime >= hour && stime < day) {
+ long time_value = stime / hour;
+ if (time_value <= 0) {
+ time_value = 1;
+ }
+ str = time_value + "小时前";
+ } else if (stime >= day && stime < weeks) {
+ long time_value = stime / day;
+ if (time_value <= 0) {
+ time_value = 1;
+ }
+ str = time_value + "天前";
+ } else if (stime >= weeks && stime < months) {
+ DateFormat df = new SimpleDateFormat(DateHolidayUtils.MMddFormat);
+ str = df.format(date);
+ } else {
+ DateFormat df = new SimpleDateFormat(DateHolidayUtils.yyyyMMddFormat);
+ str = df.format(date);
+ }
+ return str;
+ }
+
+ /**
+ * 判断指定时间是否是周末
+ *
+ * @param date
+ * 指定的时间
+ * @return true:是周末,false:非周末
+ */
+ public static boolean isWeeks(Date date) {
+ boolean isWeek = false;
+ isWeek = (getWeek(date) - 1 == 0 || getWeek(date) - 1 == 6);
+ return isWeek;
+ }
+
+ /**
+ * 得到今天的最开始时间
+ *
+ * @return 今天的最开始时间
+ */
+ public static Date getTodayBeginTime() {
+ Date beginTime = new Date();
+ beginTime = getBeginTime(beginTime);
+ return beginTime;
+ }
+
+ /**
+ * 得到指定日期的最开始时间
+ *
+ * @return 今天的最开始时间
+ */
+ public static Date getBeginTime(Date date) {
+ Date beginTime = date;
+ String beginString = getFormatDateTime(beginTime, DateHolidayUtils.yyyyMMddFormat) + " 00:00:00";
+ beginTime = str2Date(beginString, DateHolidayUtils.fullFormat);
+ return beginTime;
+ }
+
+ public static Long getBeginTimeStamp(Long timeStamp) {
+ Date beginTime = new Date(timeStamp);
+ String beginString = getFormatDateTime(beginTime, DateHolidayUtils.yyyyMMddFormat) + " 00:00:00";
+ beginTime = str2Date(beginString, DateHolidayUtils.fullFormat);
+ return beginTime.getTime();
+ }
+
+ public static String getBeginTimeStr(Date date) {
+ Date beginTime = date;
+ String beginString = getFormatDateTime(beginTime, DateHolidayUtils.yyyyMMddFormat) + " 00:00:00";
+ return beginString;
+ }
+
+
+ /**
+ * 得到今天的最后结束时间
+ *
+ * @return 今天的最后时间
+ */
+ public static Date getTodayEndTime() {
+ Date endTime = new Date();
+ endTime = getEndTime(endTime);
+ return endTime;
+ }
+
+ /**
+ * 得到指定日期的最后结束时间
+ *
+ * @return 今天的最后时间
+ */
+ public static Date getEndTime(Date date) {
+
+ Date endTime = date;
+ String beginString = getFormatDateTime(endTime, DateHolidayUtils.yyyyMMddFormat) + " 23:59:59";
+ endTime = str2Date(beginString, DateHolidayUtils.fullFormat);
+ return endTime;
+ }
+
+ /**
+ * 得到指定日期的最后结束时间
+ *
+ * @return 今天的最后时间
+ */
+ public static Date getCalEndTime(Date date) {
+
+ Date endTime = addDays(date, 1);
+ String beginString = getFormatDateTime(endTime, DateHolidayUtils.yyyyMMddFormat) + " 00:00:00";
+ endTime = str2Date(beginString, DateHolidayUtils.fullFormat);
+ return endTime;
+ }
+
+ public static String getEndTimeStr(Date date) {
+
+ Date endTime = date;
+ String endString = getFormatDateTime(endTime, DateHolidayUtils.yyyyMMddFormat) + " 23:59:59";
+ return endString;
+ }
+
+
+ /**
+ * 取得本周的开始时间
+ *
+ * @return 本周的开始时间
+ */
+ public static Date getThisWeekBeginTime() {
+ Date beginTime = null;
+ Calendar cal = Calendar.getInstance();
+ int week = getWeek(cal.getTime());
+ week = week - 1;
+ int days = 0;
+ if (week == 0) {
+ days = 6;
+ } else {
+ days = week - 1;
+ }
+ cal.add(Calendar.DAY_OF_MONTH, -days);
+ beginTime = cal.getTime();
+ return beginTime;
+ }
+
+ /**
+ * 取得指定日期所在周的开始时间
+ *
+ * @return 本周的开始时间
+ */
+ public static Date getThisWeekBeginTime(Date date) {
+ Date beginTime = null;
+ int week = getWeek(date);
+ week = week - 1;
+ int days = 0;
+ if (week == 0) {
+ days = 6;
+ } else {
+ days = week - 1;
+ }
+ beginTime = addDays(date,-days);
+ return beginTime;
+ }
+
+ /**
+ * 取得本周的开始日期
+ *
+ * @param format
+ * 时间的格式
+ * @return 指定格式的本周最开始时间
+ */
+ public static String getThisWeekBeginTimeString(String format) {
+ DateFormat df = new SimpleDateFormat(format);
+ return df.format(getThisWeekBeginTime());
+ }
+
+ /**
+ * 取得本周的结束时间
+ *
+ * @return 本周的结束时间
+ */
+ public static Date getThisWeekEndTime() {
+ Date endTime = null;
+ Calendar cal = Calendar.getInstance();
+ int week = getWeek(cal.getTime());
+ week = week - 1;
+ int days = 0;
+ if (week != 0) {
+ days = 7 - week;
+ }
+ cal.add(Calendar.DAY_OF_MONTH, days);
+ endTime = cal.getTime();
+ return endTime;
+ }
+
+ /**
+ * 取得指定日期所在周的结束时间
+ *
+ * @return 本周的结束时间
+ */
+ public static Date getThisWeekEndTime(Date date) {
+ Date endTime = null;
+ int week = getWeek(date);
+ week = week - 1;
+ int days = 0;
+ if (week != 0) {
+ days = 7 - week;
+ }
+ endTime = addDays(date, days);
+ return endTime;
+ }
+
+ /**
+ * 取得本周的结束日期
+ *
+ * @param format
+ * 时间的格式
+ * @return 指定格式的本周结束时间
+ */
+ public static String getThisWeekEndTimeString(String format) {
+ DateFormat df = new SimpleDateFormat(format);
+ return df.format(getThisWeekEndTime());
+ }
+
+ /**
+ * 取得两时间相差的天数
+ *
+ * @param from
+ * 第一个时间
+ * @param to
+ * 第二个时间
+ * @return 相差的天数
+ */
+ public static long getBetweenDays(Date from, Date to) {
+ long days = 0;
+ long dayTime = 24 * 60 * 60 * 1000;
+ long fromTime = from.getTime();
+ long toTime = to.getTime();
+// long times = Math.abs(fromTime - toTime);
+ Long times = fromTime - toTime;
+ days = times / dayTime;
+ return days;
+ }
+
+ /**
+ * 获取时间相隔年份
+ * @author zhanglei 2017-10-20 下午2:51:10
+ * @param from
+ * @param to
+ * @return
+ */
+ public static long getBetweenYears(Date from, Date to) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(from);
+ int year = cal.get(Calendar.YEAR);
+ cal.setTime(to);
+ int year2 = cal.get(Calendar.YEAR);
+ long years = Math.abs(year2 - year);
+ return years;
+ }
+
+ /**
+ * 取得两时间相差的小时数
+ *
+ * @param from
+ * 第一个时间
+ * @param to
+ * 第二个时间
+ * @return 相差的小时数
+ */
+ public static BigDecimal getBetweenHours(Date from, Date to) {
+ long hours = 0;
+ long hourTime = 60 * 60 * 1000;
+ long fromTime = from.getTime();
+ long toTime = to.getTime();
+ long times = Math.abs(fromTime - toTime);
+ return BigDecimal.valueOf(times).divide(BigDecimal.valueOf(hourTime), 2, BigDecimal.ROUND_DOWN);
+ }
+
+ /**
+ * 取得两时间相差的分钟数
+ *
+ * @param from
+ * 第一个时间
+ * @param to
+ * 第二个时间
+ * @return 相差的分钟数
+ */
+ public static long getBetweenMinutes(Date from, Date to) {
+ long m = 0;
+ long mTime = 60 * 1000;
+ long fromTime = from.getTime();
+ long toTime = to.getTime();
+ long times = Math.abs(fromTime - toTime);
+ m = times / mTime;
+ return m;
+ }
+
+ /**
+ * 取得两时间相差的秒数
+ *
+ * @param from
+ * 第一个时间
+ * @param to
+ * 第二个时间
+ * @return 相差的秒数
+ */
+ public static long getBetweenSeconds(Date from, Date to) {
+ long s = 0;
+ long sTime = 1000;
+ long fromTime = from.getTime();
+ long toTime = to.getTime();
+ long times = Math.abs(fromTime - toTime);
+ s = times / sTime;
+ return s;
+ }
+
+ /**
+ * 取得在指定时间上加减 minute 分钟后的时间
+ * @author zhanglei 2015 三月 24 10:15:21
+ * @param date
+ * @param minute
+ * @return
+ */
+ public static Date addMinutes(Date date, int minute) {
+ Date time = null;
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ cal.add(Calendar.MINUTE, minute);
+ time = cal.getTime();
+ return time;
+ }
+
+
+ /**
+ * 取得在指定时间上加减days天后的时间
+ *
+ * @param date
+ * 指定的时间
+ * @param days
+ * 天数,正为加,负为减
+ * @return 在指定时间上加减days天后的时间
+ */
+ public static Date addDays(Date date, int days) {
+ Date time = null;
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ cal.add(Calendar.DAY_OF_MONTH, days);
+ time = cal.getTime();
+ return time;
+ }
+
+ /**
+ * 取得在指定时间上加减months月后的时间
+ *
+ * @param date
+ * 指定时间
+ * @param months
+ * 月数,正为加,负为减
+ * @return 在指定时间上加减months月后的时间
+ */
+ public static Date addMonths(Date date, int months) {
+ Date time = null;
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ cal.add(Calendar.MONTH, months);
+ time = cal.getTime();
+ return time;
+ }
+
+ /**
+ * 取得在指定时间上加减years年后的时间
+ *
+ * @param date
+ * 指定时间
+ * @param years
+ * 年数,正为加,负为减
+ * @return 在指定时间上加减years年后的时间
+ */
+ public static Date addYears(Date date, int years) {
+ Date time = null;
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ cal.add(Calendar.YEAR, years);
+ time = cal.getTime();
+ return time;
+ }
+
+ /**
+ * 方法说明:"yyyyMMddHHmmss"格式的字符串转成日期
+ *
+ * @author zhanglei
+ * @createDate 2013-10-24 上午01:35:15
+ * @param str_date
+ * @return date
+ */
+ public static Date str2Date(String str_date, String format) {
+ Date date = null;
+ DateFormat df = new SimpleDateFormat(format == null ? DateHolidayUtils.yyyyMMddHHmmss:format);
+ try {
+ date = df.parse(str_date);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return date;
+ }
+
+ /**
+ * 获取当前年度
+ *
+ * @return
+ */
+ public static String getCurYear() {
+ Calendar calendar = Calendar.getInstance();
+ int yearInt = calendar.get(Calendar.YEAR);
+ return String.valueOf(yearInt);
+ }
+
+ public static Date getFirstDayOfYear(String year) {
+ Calendar calendar = Calendar.getInstance();
+ if (year != null && !year.isEmpty()) {
+ int yearInt = Integer.valueOf(year);
+ calendar.set(Calendar.YEAR, yearInt);
+ }
+ calendar.set(Calendar.MONTH, 0);
+ calendar.set(Calendar.DAY_OF_MONTH, 1);
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ return calendar.getTime();
+ }
+ public static Date getLastDayOfYear(String year) {
+ Calendar calendar = Calendar.getInstance();
+ if (year != null && !year.isEmpty()) {
+ int yearInt = Integer.valueOf(year);
+ calendar.set(Calendar.YEAR, yearInt);
+ }
+ calendar.set(Calendar.MONTH, 11);
+ calendar.set(Calendar.DAY_OF_MONTH, 31);
+ calendar.set(Calendar.HOUR_OF_DAY, 23);
+ calendar.set(Calendar.MINUTE, 59);
+ calendar.set(Calendar.SECOND, 59);
+ return calendar.getTime();
+ }
+
+ public static Date getLastDayOfQuarter(String year, int quarter) {
+ Calendar calendar = Calendar.getInstance();
+ if (year != null && !year.isEmpty()) {
+ int yearInt = Integer.valueOf(year);
+ calendar.set(Calendar.YEAR, yearInt);
+ }
+ if (quarter == 1) {
+ calendar.set(Calendar.MONTH, 2);
+ calendar.set(Calendar.DAY_OF_MONTH, 31);
+ } else if (quarter == 2) {
+ calendar.set(Calendar.MONTH, 5);
+ calendar.set(Calendar.DAY_OF_MONTH, 30);
+ } else if (quarter == 3) {
+ calendar.set(Calendar.MONTH, 8);
+ calendar.set(Calendar.DAY_OF_MONTH, 30);
+ } else if (quarter == 4) {
+ calendar.set(Calendar.MONTH, 11);
+ calendar.set(Calendar.DAY_OF_MONTH, 31);
+ }
+ return calendar.getTime();
+ }
+
+ /**
+ * 获取一个月的第一天
+ * @param dateStr
+ * @return
+ * @throws ParseException
+ */
+ public static Date getMonthFirstDate(String dateStr) throws ParseException {
+ DateFormat df = new SimpleDateFormat(yyyyMMFormat);
+ Date data= df.parse(dateStr);
+ return data;
+ }
+
+ /**
+ * 获取一个月的最后一天
+ *
+ * @param dateStr
+ * yyyy-MM
+ * @return
+ * @throws ParseException
+ */
+ public static Date getMonthLastDate(String dateStr) throws ParseException {
+ DateFormat df = new SimpleDateFormat(yyyyMMFormat);
+ Date data = df.parse(dateStr);
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(data);
+ int value = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
+ calendar.set(Calendar.DAY_OF_MONTH, value);
+ return calendar.getTime();
+ }
+
+ public static void main(String[] args) {
+ System.out.println(DateHolidayUtils.str2Date("2020年10月28日", DateHolidayUtils.yyyyMMddChineseFormat));
+ System.out.println(new Date(1595174400000L));
+ // 2022-11-2 14:0:0
+ // 2022-11-2 23:59:59
+ System.out.println(getBetweenHours(new Date(1667368800000L), getEndTime(new Date(1667368800000L))));
+ System.out.println(getBetweenHours(new Date(1667368800000L), new Date(1667404799000L)));
+ System.out.println(getBetweenHours(new Date(1667368800000L), new Date(1667404800000L)));
+ }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
index c64f1f8a1..1e1954b8f 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
@@ -1,10 +1,12 @@
package com.ruoyi.common.utils;
+import cn.hutool.core.util.ObjectUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.lang.management.ManagementFactory;
+import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
@@ -99,6 +101,11 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
return DateFormatUtils.format(now, "yyyyMMdd");
}
+ public static String dateTime(String format) {
+ Date now = new Date();
+ return DateFormatUtils.format(now, format);
+ }
+
/**
* 日期型字符串转化为日期 格式
*/
@@ -165,4 +172,24 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
+
+ /**
+ * 校验是否符合时间格式
+ * @param sDate
+ * @param format
+ * @return
+ */
+ public static boolean checkDate(String sDate,String format){
+ int legalLen = sDate.length();
+ if (ObjectUtil.isNull(legalLen) || legalLen==0){
+ return false;
+ }
+ DateFormat formatter = new SimpleDateFormat(format);
+ try {
+ Date date = formatter.parse(sDate);
+ return sDate.equals(formatter.format(date));
+ } catch (Exception e) {
+ return false;
+ }
+ }
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/FutureUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/FutureUtil.java
new file mode 100644
index 000000000..eea2d7d07
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/FutureUtil.java
@@ -0,0 +1,168 @@
+package com.ruoyi.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.concurrent.*;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+* 多任务处理工具类
+* @Author WhHao
+* @Date 2022/8/10 16:04
+* @Return
+*/
+@Slf4j
+public class FutureUtil {
+
+ /**
+ * cpu 核心数
+ */
+ private static final int AVALIABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();
+
+ // 最大超时时间
+ private static final int TIMEOUT_VALUE = 1500;
+ // 时间单位
+ private static final TimeUnit TIMEOUT_UNIT = TimeUnit.MILLISECONDS;
+
+
+ /**
+ * Singleton delay scheduler, used only for starting and * cancelling tasks.
+ */
+ public static final class Delayer {
+
+ static final ScheduledThreadPoolExecutor delayer;
+
+ /**
+ * 异常线程,不做请求处理,只抛出异常
+ */
+ static {
+ delayer = new ScheduledThreadPoolExecutor(1, new DaemonThreadFactory());
+ delayer.setRemoveOnCancelPolicy(true);
+ }
+
+ static ScheduledFuture> delay(Runnable command, long delay, TimeUnit unit) {
+ return delayer.schedule(command, delay, unit);
+ }
+
+ static final class DaemonThreadFactory implements ThreadFactory {
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread t = new Thread(r);
+ t.setDaemon(true);
+ t.setName("CompletableFutureScheduler");
+ return t;
+ }
+ }
+ }
+
+ /**
+ * 根据服务器cpu自定义线程池
+ */
+ private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
+ AVALIABLE_PROCESSORS,
+ 3 * AVALIABLE_PROCESSORS,
+ 3,
+ TimeUnit.SECONDS,
+ new LinkedBlockingDeque<>(20),
+ new ThreadPoolExecutor.CallerRunsPolicy()
+ );
+
+ /**
+ * 有返回值的异步
+ * @param supplier
+ * @param
+ * @return
+ */
+ public static CompletableFuture supplyAsync(Supplier supplier){
+ return supplyAsync(TIMEOUT_VALUE,TIMEOUT_UNIT,supplier);
+ }
+
+ /**
+ * 有返回值的异步 - 可设置超时时间
+ * @param timeout
+ * @param unit
+ * @param supplier
+ * @param
+ * @return
+ */
+ public static CompletableFuture supplyAsync(long timeout, TimeUnit unit,Supplier supplier){
+ return CompletableFuture.supplyAsync(supplier, threadPoolExecutor)
+ .applyToEither(timeoutAfter(timeout,unit), Function.identity())
+ .exceptionally(throwable -> {
+ throwable.printStackTrace();
+ log.error(throwable.getMessage());
+ return null;
+ });
+ }
+
+ /**
+ * 无返回值的异步
+ * @param runnable
+ * @return
+ */
+ public static CompletableFuture runAsync(Runnable runnable){
+ return runAsync(TIMEOUT_VALUE,TIMEOUT_UNIT,runnable);
+ }
+
+ /**
+ * 无返回值的异步 - 可设置超时时间
+ * @param runnable
+ * @return
+ */
+ public static CompletableFuture runAsync(long timeout, TimeUnit unit,Runnable runnable){
+ return CompletableFuture.runAsync(runnable,threadPoolExecutor)
+ .applyToEither(timeoutAfter(timeout,unit), Function.identity())
+ .exceptionally(throwable -> {
+ throwable.printStackTrace();
+ log.error(throwable.getMessage());
+ return null;
+ });
+ }
+
+ /**
+ * 统一处理异步结果
+ * @param futures
+ * @return
+ */
+ public static CompletableFuture allOf(CompletableFuture... futures){
+ return allOf(TIMEOUT_VALUE,TIMEOUT_UNIT,futures);
+ }
+
+ /**
+ * 统一处理异步结果 - 可设置超时时间
+ * @param futures
+ * @return
+ */
+ public static CompletableFuture allOf(long timeout, TimeUnit unit,CompletableFuture... futures){
+ return CompletableFuture.allOf(futures)
+ .applyToEither(timeoutAfter(timeout,unit), Function.identity())
+ .exceptionally(throwable -> {
+ throwable.printStackTrace();
+ log.error(throwable.getMessage());
+ return null;
+ });
+ }
+
+ /**
+ * 异步超时处理
+ * @param timeout
+ * @param unit
+ * @param
+ * @return
+ */
+ public static CompletableFuture timeoutAfter(long timeout, TimeUnit unit) {
+ CompletableFuture result = new CompletableFuture();
+ // timeout 时间后 抛出TimeoutException 类似于sentinel / watcher
+ Delayer.delayer.schedule(() -> result.completeExceptionally(new TimeoutException()), timeout, unit);
+ return result;
+ }
+
+ public static CompletableFuture timeoutAfter() {
+ CompletableFuture result = new CompletableFuture();
+ // timeout 时间后 抛出TimeoutException 类似于sentinel / watcher
+ Delayer.delayer.schedule(() -> result.completeExceptionally(new TimeoutException()), TIMEOUT_VALUE, TIMEOUT_UNIT);
+ return result;
+ }
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/MySerializerUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/MySerializerUtils.java
new file mode 100644
index 000000000..822fac5e5
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/MySerializerUtils.java
@@ -0,0 +1,16 @@
+package com.ruoyi.common.utils;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import java.io.IOException;
+
+public class MySerializerUtils extends JsonSerializer {
+ @Override
+ public void serialize(Long id, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
+ String statusStr = String.valueOf(id);
+ jsonGenerator.writeString(statusStr);
+ }
+ }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/OpenUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/OpenUtils.java
new file mode 100644
index 000000000..e7bae18df
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/OpenUtils.java
@@ -0,0 +1,92 @@
+package com.ruoyi.common.utils;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.crypto.Mode;
+import cn.hutool.crypto.Padding;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.digest.MD5;
+import cn.hutool.crypto.symmetric.AES;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.domain.entity.GaoXinCardInfo;
+import com.ruoyi.common.exception.ServiceException;
+
+/**
+ * @author Administrator
+ * 对外所需要的工具类
+ */
+
+
+public class OpenUtils {
+ private static final String appsecret ="JXYB7KpXlH9i0CL6";
+ private static final String aesKey = "74242EAFE97F18BFAE9D2682590B6614";
+ private static final String iv = "74242EAFE97F18BF";
+ private static final String id="2023062804031";
+// private static final String url ="http://162.14.100.54:9010/index.php/Api/renju/get_user_info";//测试
+ private static final String url ="http://118.122.86.24:8016/index.php/Api/renju/get_user_info";// 正式地址
+
+ public static R> getGaoXinCardInfo(String cardId){
+ AES aes = new AES(Mode.CBC, Padding.PKCS5Padding,aesKey.getBytes(),iv.getBytes());
+ String param=aes.encryptBase64(
+ new JSONObject()
+ .set("id_card",cardId)
+ .toStringPretty());
+ MD5 md5 = SecureUtil.md5();
+ String sign=md5.digestHex(id+param+appsecret);
+ JSONObject jsonObject = new JSONObject()
+ .set("id",id)
+ .set("param",param)
+ .set("sign",sign);
+ try {
+ String content = HttpRequest.post(url)
+ .timeout(5000)
+ .body(jsonObject.toStringPretty())
+ .execute()
+ .body();
+ System.out.println("content = " + content);
+ JSONObject jsonObject1 = JSONUtil.parseObj(content);
+ Integer code = jsonObject1.getInt("code");
+ Object data = jsonObject1.get("data");
+ String message = jsonObject1.getStr("message");
+ if (code==200){
+ if (ObjectUtil.isNull(data) || ObjectUtil.isEmpty(data)){
+ return R.fail("暂未获取到当前"+cardId+"人才认定信息,如有疑问请联系客服人员! 电话:19940594954");
+ }else {
+ GaoXinCardInfo gaoXinCardInfo = JsonUtils.parseObject(JSONUtil.toJsonPrettyStr(data), GaoXinCardInfo.class);
+ //判断值是否为空
+ if (ObjectUtil.isEmpty(gaoXinCardInfo.getName())){
+ return R.fail("获取人才认定数据接口返回异常,异常信息:姓名为空!请联系客服人员! 电话:19940594954");
+ }else if (ObjectUtil.isEmpty(gaoXinCardInfo.getCard_id())){
+ return R.fail("获取人才认定数据接口返回异常,异常信息:身份证为空!请联系客服人员! 电话:19940594954");
+ }else if (ObjectUtil.isEmpty(gaoXinCardInfo.getSex())){
+ return R.fail("获取人才认定数据接口返回异常,异常信息:性别为空!请联系客服人员! 电话:19940594954");
+ }else if (ObjectUtil.isEmpty(gaoXinCardInfo.getNationality())){
+ return R.fail("获取人才认定数据接口返回异常,异常信息:国籍为空!请联系客服人员! 电话:19940594954");
+ }else if (ObjectUtil.isEmpty(gaoXinCardInfo.getEducation())){
+ return R.fail("获取人才认定数据接口返回异常,异常信息:学历为空!请联系客服人员! 电话:19940594954");
+ }else if (ObjectUtil.isEmpty(gaoXinCardInfo.getDistrict())){
+ return R.fail("获取人才认定数据接口返回异常,异常信息:单位区域为空!请联系客服人员! 电话:19940594954");
+ }else if (ObjectUtil.isEmpty(gaoXinCardInfo.getPhone())){
+ return R.fail("获取人才认定数据接口返回异常,异常信息:手机号为空!请联系客服人员! 电话:19940594954");
+ }else if (ObjectUtil.isEmpty(gaoXinCardInfo.getCompany_name())){
+ return R.fail("获取人才认定数据接口返回异常,异常信息:公司名称为空!请联系客服人员! 电话:19940594954");
+ }else if (ObjectUtil.isEmpty(gaoXinCardInfo.getType())){
+ return R.fail("获取人才认定数据接口返回异常,异常信息:人才类型为空!请联系客服人员! 电话:19940594954");
+ }
+ gaoXinCardInfo.setType(gaoXinCardInfo.getType());
+ gaoXinCardInfo.setNationality(gaoXinCardInfo.getNationality());
+ return R.ok(gaoXinCardInfo);
+ }
+ }else if (code==400){
+ return R.fail("获取人才认定数据接口返回异常,异常信息:"+message+"请联系客服人员! 电话:19940594954");
+ }else {
+ return R.fail("人才认定接口请求未知异常");
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("人才认定接口请求错误");
+ }
+ }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/RSAUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/RSAUtil.java
new file mode 100644
index 000000000..5f8ac3c2d
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/RSAUtil.java
@@ -0,0 +1,34 @@
+package com.ruoyi.common.utils;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.antherd.smcrypto.sm2.Sm2;
+
+/**
+ * RSA加解密工具类
+ * @author Administrator
+ */
+public class RSAUtil {
+
+
+ public static final String PRIVATE_KEY = "9cefdfcb925a32e10206d3a693ba204632c59e5f9a171faebb814885191dd35e";
+ public static final String VUE_PUBLIC_KEY = "048af4184056315a9ecfcc14280b32504ba194ec8dd0e06b298c4a1aa557e7e9a5d15e1293392f741f7fb31a82e55785b7f1880d61b57def1e38e3f06435fb0502";
+ /**
+ * 公钥加密
+ */
+ public static String publicKeyEncryptBase64(String data,String outPublicKey){
+ if (ObjectUtil.isNotEmpty(outPublicKey)){
+ return Sm2.doEncrypt(data, outPublicKey);
+ }
+ return Sm2.doEncrypt(data, VUE_PUBLIC_KEY);
+ }
+
+ /**
+ * 私钥解密
+ */
+ public static String privateKeyDecryptStr(String data,String privateKey){
+ if (ObjectUtil.isNotEmpty(privateKey)){
+ return Sm2.doDecrypt(data, privateKey);
+ }
+ return Sm2.doDecrypt(data,PRIVATE_KEY);
+ }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/StrUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StrUtils.java
new file mode 100644
index 000000000..13a8479d4
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StrUtils.java
@@ -0,0 +1,96 @@
+package com.ruoyi.common.utils;
+
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * @author yaohuaipeng
+ * @date 2018/10/26-16:16
+ */
+public class StrUtils {
+ /**
+ * 把逗号分隔的字符串转换字符串数组
+ *
+ * @param str
+ * @return
+ */
+ public static String[] splitStr2StrArr(String str,String split) {
+ if (str != null && !str.equals("")) {
+ return str.split(split);
+ }
+ return null;
+ }
+
+
+ /**
+ * 把逗号分隔字符串转换List的Long
+ *
+ * @param str
+ * @return
+ */
+ public static List splitStr2LongArr(String str) {
+ String[] strings = splitStr2StrArr(str,",");
+ if (strings == null) return null;
+
+ List result = new ArrayList<>();
+ for (String string : strings) {
+ result.add(Long.parseLong(string));
+ }
+
+ return result;
+ }
+ /**
+ * 把逗号分隔字符串转换List的Long
+ *
+ * @param str
+ * @return
+ */
+ public static List splitStr2LongArr(String str,String split) {
+ String[] strings = splitStr2StrArr(str,split);
+ if (strings == null) return null;
+
+ List result = new ArrayList<>();
+ for (String string : strings) {
+ result.add(Long.parseLong(string));
+ }
+
+ return result;
+ }
+
+ public static String getRandomString(int length) {
+ String str = "0123456789";
+ Random random = new Random();
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < length; i++) {
+ int number = random.nextInt(10);
+ sb.append(str.charAt(number));
+ }
+ return sb.toString();
+
+ }
+
+ public static String getComplexRandomString(int length) {
+ String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ SecureRandom random = new SecureRandom();
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < length; i++) {
+ int number = random.nextInt(62);
+ sb.append(str.charAt(number));
+ }
+ return sb.toString();
+ }
+
+ public static String convertPropertiesToHtml(String properties){
+ //1:容量:6:32GB_4:样式:12:塑料壳
+ StringBuilder sBuilder = new StringBuilder();
+ String[] propArr = properties.split("_");
+ for (String props : propArr) {
+ String[] valueArr = props.split(":");
+ sBuilder.append(valueArr[1]).append(":").append(valueArr[3]).append("
");
+ }
+ return sBuilder.toString();
+ }
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
index 2a5bd488b..ca152405a 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
@@ -171,6 +171,15 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
return StrUtil.toUnderlineCase(str);
}
+ /**
+ * 字母转大写
+ * @param str
+ * @return
+ */
+ public static String toUpperCase(String str) {
+ return str.toUpperCase();
+ }
+
/**
* 是否包含字符串
*
@@ -322,4 +331,17 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
.collect(Collectors.toList());
}
+ /**
+ * @param str
+ * @function 判断输入的数据是否是大于等于零的整数
+ */
+ public static boolean isNumeric(String str) {
+ for (int i = str.length(); --i >= 0;) {
+ if (!Character.isDigit(str.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/XuexinUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/XuexinUtils.java
new file mode 100644
index 000000000..caded7d0f
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/XuexinUtils.java
@@ -0,0 +1,4 @@
+package com.ruoyi.common.utils;
+
+public class XuexinUtils {
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java
new file mode 100644
index 000000000..85f1a27e6
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java
@@ -0,0 +1,95 @@
+package com.ruoyi.common.utils.file;
+
+import java.io.File;
+import java.util.Objects;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * 文件类型工具类
+ *
+ * @author ruoyi
+ */
+public class FileTypeUtils
+{
+ /**
+ * 获取文件类型
+ *
+ * 例如: ruoyi.txt, 返回: txt
+ *
+ * @param file 文件名
+ * @return 后缀(不含".")
+ */
+ public static String getFileType(File file)
+ {
+ if (null == file)
+ {
+ return StringUtils.EMPTY;
+ }
+ return getFileType(file.getName());
+ }
+
+ /**
+ * 获取文件类型
+ *
+ * 例如: ruoyi.txt, 返回: txt
+ *
+ * @param fileName 文件名
+ * @return 后缀(不含".")
+ */
+ public static String getFileType(String fileName)
+ {
+ int separatorIndex = fileName.lastIndexOf(".");
+ if (separatorIndex < 0)
+ {
+ return "";
+ }
+ return fileName.substring(separatorIndex + 1).toLowerCase();
+ }
+
+ /**
+ * 获取文件名的后缀
+ *
+ * @param file 表单文件
+ * @return 后缀名
+ */
+ public static final String getExtension(MultipartFile file)
+ {
+ String extension = FilenameUtils.getExtension(file.getOriginalFilename());
+ if (StringUtils.isEmpty(extension))
+ {
+ extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
+ }
+ return extension;
+ }
+
+ /**
+ * 获取文件类型
+ *
+ * @param photoByte 文件字节码
+ * @return 后缀(不含".")
+ */
+ public static String getFileExtendName(byte[] photoByte)
+ {
+ String strFileExtendName = "JPG";
+ if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
+ && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))
+ {
+ strFileExtendName = "GIF";
+ }
+ else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))
+ {
+ strFileExtendName = "JPG";
+ }
+ else if ((photoByte[0] == 66) && (photoByte[1] == 77))
+ {
+ strFileExtendName = "BMP";
+ }
+ else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))
+ {
+ strFileExtendName = "PNG";
+ }
+ return strFileExtendName;
+ }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java
index 6ca97fe60..e3cf52e01 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java
@@ -37,4 +37,23 @@ public class MimeTypeUtils {
// pdf
"pdf"};
+ public static String getExtension(String prefix)
+ {
+ switch (prefix)
+ {
+ case IMAGE_PNG:
+ return "png";
+ case IMAGE_JPG:
+ return "jpg";
+ case IMAGE_JPEG:
+ return "jpeg";
+ case IMAGE_BMP:
+ return "bmp";
+ case IMAGE_GIF:
+ return "gif";
+ default:
+ return "";
+ }
+ }
+
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MyFileUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MyFileUtils.java
new file mode 100644
index 000000000..190e04ae4
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MyFileUtils.java
@@ -0,0 +1,435 @@
+package com.ruoyi.common.utils.file;
+
+import cn.hutool.core.io.resource.ClassPathResource;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 文件处理工具类
+ *
+ * @author ruoyi
+ */
+public class MyFileUtils extends FileUtils
+{
+ /** 字符常量:斜杠 {@code '/'} */
+ public static final char SLASH = '/';
+
+ /** 字符常量:反斜杠 {@code '\\'} */
+ public static final char BACKSLASH = '\\';
+
+ public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
+
+ /**
+ * 输出指定文件的byte数组
+ *
+ * @param filePath 文件路径
+ * @param fileName 文件名字
+ * @return
+ */
+ public static void writeBytes(String filePath, String fileName) throws IOException
+ {
+ FileInputStream fis = null;
+ FileOutputStream os = null;
+ try
+ {
+ File file = new File(filePath);
+ os = new FileOutputStream(fileName);
+ if (!file.exists())
+ {
+ throw new FileNotFoundException(filePath);
+ }
+ fis = new FileInputStream(file);
+
+ byte[] b = new byte[1024];
+ int length;
+ while ((length = fis.read(b)) > 0)
+ {
+ os.write(b, 0, length);
+ }
+ }
+ catch (IOException e)
+ {
+ //不抛异常
+ e.printStackTrace();
+// throw e;
+ }
+ finally
+ {
+ if (os != null)
+ {
+ try
+ {
+ os.close();
+ }
+ catch (IOException e1)
+ {
+ e1.printStackTrace();
+ }
+ }
+ if (fis != null)
+ {
+ try
+ {
+ fis.close();
+ }
+ catch (IOException e1)
+ {
+ e1.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static void downLoadPic(String str,String fileName) {
+ // 完成从网络上下载图片的功能
+ try {
+ // 建立连接
+ URL url = new URL(str);
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("GET");//POST
+ //防止屏蔽程序抓取而返回403错误
+ conn.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
+ conn.setRequestProperty("Referer","https://rcaj.cdhtgycs.cn");
+ conn.setConnectTimeout(5000);
+ conn.setReadTimeout(5000);
+ int responseCode = conn.getResponseCode();
+ System.out.println("responseCode = " + responseCode);
+ InputStream inputStream = conn.getInputStream();
+ byte[] temp = new byte[inputStream.available()];
+ if (responseCode==200) {
+ if (temp.length==0) {
+ ClassPathResource classPathResource = new ClassPathResource("/404.jpg");
+ inputStream = classPathResource.getStream();
+ temp = new byte[inputStream.available()];
+ }
+ FileOutputStream fos = new FileOutputStream(fileName);
+ int len = 0;
+ while ((len = inputStream.read(temp)) != -1) {
+ fos.write(temp, 0, len);
+ }
+ inputStream.close();
+ fos.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ /**
+ * 对中文字符进行UTF-8编码
+ * @param source 要转义的字符串
+ * @return
+ * @throws UnsupportedEncodingException
+ */
+ public static String tranformStyle(String source) throws UnsupportedEncodingException
+ {
+ char[] arr = source.toCharArray();
+ StringBuilder sb = new StringBuilder();
+ for(int i = 0; i < arr.length; i++)
+ {
+ char temp = arr[i];
+ if(isChinese(temp))
+ {
+ sb.append(URLEncoder.encode("" + temp, "UTF-8"));
+ continue;
+ }
+ sb.append(arr[i]);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 获取字符的编码值
+ * @param s
+ * @return
+ * @throws UnsupportedEncodingException
+ */
+ public static int getValue(char s) throws UnsupportedEncodingException
+ {
+ String temp = (URLEncoder.encode("" + s, "GBK")).replace("%", "");
+ if(temp.equals(s + ""))
+ {
+ return 0;
+ }
+ char[] arr = temp.toCharArray();
+ int total = 0;
+ for(int i = 0; i < arr.length; i++)
+ {
+ try
+ {
+ int t = Integer.parseInt((arr[i] + ""), 16);
+ total = total * 16 + t;
+ }
+ catch(NumberFormatException e)
+ {
+ e.printStackTrace();
+ return 0;
+ }
+ }
+ return total;
+ }
+
+ /**
+ * 判断是不是中文字符
+ * @param c
+ * @return
+ */
+ public static boolean isChinese(char c)
+ {
+
+ Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
+
+ if(ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
+
+ || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
+
+ || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
+
+ || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
+
+ || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
+
+ || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS)
+ {
+
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+ /**
+ * 删除文件
+ *
+ * @param filePath 文件
+ * @return
+ */
+ public static boolean deleteFile(String filePath)
+ {
+ boolean flag = false;
+ File file = new File(filePath);
+ // 路径为文件且不为空则进行删除
+ if (file.isFile() && file.exists())
+ {
+ file.delete();
+ flag = true;
+ }
+ return flag;
+ }
+
+ /**
+ * 文件名称验证
+ *
+ * @param filename 文件名称
+ * @return true 正常 false 非法
+ */
+ public static boolean isValidFilename(String filename)
+ {
+ return filename.matches(FILENAME_PATTERN);
+ }
+
+ /* public static void main(String[] args) {
+ boolean b = checkAllowDownload("C:\\Users\\vimdr\\Pictures\\Camera Roll\\Snipaste_2021-06-03_15-11-34.png");
+ System.out.println(b);
+ }*/
+
+ /**
+ * 检查文件是否可下载
+ *
+ * @param resource 需要下载的文件
+ * @return true 正常 false 非法
+ */
+ public static boolean checkAllowDownload(String resource)
+ {
+ // 禁止目录上跳级别
+ if (StringUtils.contains(resource, ".."))
+ {
+ return false;
+ }
+
+ // 检查允许下载的文件规则
+ if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))
+ {
+ return true;
+ }
+
+ // 不在允许下载的文件规则
+ return false;
+ }
+
+ /**
+ * 下载文件名重新编码
+ *
+ * @param request 请求对象
+ * @param fileName 文件名
+ * @return 编码后的文件名
+ */
+ public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException
+ {
+ final String agent = request.getHeader("USER-AGENT");
+ String filename = fileName;
+ if (agent.contains("MSIE"))
+ {
+ // IE浏览器
+ filename = URLEncoder.encode(filename, "utf-8");
+ filename = filename.replace("+", " ");
+ }
+ else if (agent.contains("Firefox"))
+ {
+ // 火狐浏览器
+ filename = new String(fileName.getBytes(), "ISO8859-1");
+ }
+ else if (agent.contains("Chrome"))
+ {
+ // google浏览器
+ filename = URLEncoder.encode(filename, "utf-8");
+ }
+ else
+ {
+ // 其它浏览器
+ filename = URLEncoder.encode(filename, "utf-8");
+ }
+ return filename;
+ }
+
+ /**
+ * 返回文件名
+ *
+ * @param filePath 文件
+ * @return 文件名
+ */
+ public static String getName(String filePath)
+ {
+ if (null == filePath)
+ {
+ return null;
+ }
+ int len = filePath.length();
+ if (0 == len)
+ {
+ return filePath;
+ }
+ if (isFileSeparator(filePath.charAt(len - 1)))
+ {
+ // 以分隔符结尾的去掉结尾分隔符
+ len--;
+ }
+
+ int begin = 0;
+ char c;
+ for (int i = len - 1; i > -1; i--)
+ {
+ c = filePath.charAt(i);
+ if (isFileSeparator(c))
+ {
+ // 查找最后一个路径分隔符(/或者\)
+ begin = i + 1;
+ break;
+ }
+ }
+
+ return filePath.substring(begin, len);
+ }
+
+ /**
+ * 是否为Windows或者Linux(Unix)文件分隔符
+ * Windows平台下分隔符为\,Linux(Unix)为/
+ *
+ * @param c 字符
+ * @return 是否为Windows或者Linux(Unix)文件分隔符
+ */
+ public static boolean isFileSeparator(char c)
+ {
+ return SLASH == c || BACKSLASH == c;
+ }
+
+ /**
+ * 下载文件名重新编码
+ *
+ * @param response 响应对象
+ * @param realFileName 真实文件名
+ * @return
+ */
+ public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException
+ {
+ String percentEncodedFileName = percentEncode(realFileName);
+
+ StringBuilder contentDispositionValue = new StringBuilder();
+ contentDispositionValue.append("attachment; filename=")
+ .append(percentEncodedFileName)
+ .append(";")
+ .append("filename*=")
+ .append("utf-8''")
+ .append(percentEncodedFileName);
+
+ response.setHeader("Content-disposition", contentDispositionValue.toString());
+ }
+
+ /**
+ * 百分号编码工具方法
+ *
+ * @param s 需要百分号编码的字符串
+ * @return 百分号编码后的字符串
+ */
+ public static String percentEncode(String s) throws UnsupportedEncodingException
+ {
+ String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
+ return encode.replaceAll("\\+", "%20");
+ }
+
+ /**
+ * 将本地图片进行Base64位编码
+ *
+ * @param
+ * @return
+ */
+ public static String encodeImgageToBase64(File imageFile) {
+ // 将图片文件转化为字节数组字符串,并对其进行Base64编码处理
+ // 其进行Base64编码处理
+ byte[] data = null;
+ // 读取图片字节数组
+ try {
+ InputStream in = new FileInputStream(imageFile);
+ data = new byte[in.available()];
+ in.read(data);
+ in.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ // 对字节数组Base64编码
+// BASE64Encoder encoder = new BASE64Encoder();
+ return Base64.encodeBase64String(data);
+// return encoder.encode(data);// 返回Base64编码过的字节数组字符串
+ }
+
+
+ public static File MultipartFileToFile(MultipartFile multipartFile) {
+ // 获取文件名
+ String fileName = multipartFile.getOriginalFilename();
+ // 获取文件后缀
+ String suffix = fileName.substring(fileName.lastIndexOf("."));
+ try {
+ File file = File.createTempFile(System.currentTimeMillis() + "", suffix);
+ //multipartFile.transferTo(file);
+ FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file);
+ return file;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/DeleteFileUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/DeleteFileUtil.java
new file mode 100644
index 000000000..ccea03b4e
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/DeleteFileUtil.java
@@ -0,0 +1,122 @@
+package com.ruoyi.common.utils.poi;
+
+/**
+ * Created by shuaibin_yang on 2019/5/9 0009.
+ */
+import java.io.File;
+
+/**
+ * 删除文件和目录
+ *
+ */
+public class DeleteFileUtil {
+
+ /**
+ * 删除文件,可以是文件或文件夹
+ *
+ * @param fileName
+ * 要删除的文件名
+ * @return 删除成功返回true,否则返回false
+ */
+ public static boolean delete(String fileName) {
+ File file = new File(fileName);
+ if (!file.exists()) {
+ System.out.println("删除文件失败:" + fileName + "不存在!");
+ return false;
+ } else {
+ if (file.isFile())
+ return deleteFile(fileName);
+ else
+ return deleteDirectory(fileName);
+ }
+ }
+
+ /**
+ * 删除单个文件
+ *
+ * @param fileName
+ * 要删除的文件的文件名
+ * @return 单个文件删除成功返回true,否则返回false
+ */
+ public static boolean deleteFile(String fileName) {
+ File file = new File(fileName);
+ // 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
+ if (file.exists() && file.isFile()) {
+ if (file.delete()) {
+ System.out.println("删除单个文件" + fileName + "成功!");
+ return true;
+ } else {
+ System.out.println("删除单个文件" + fileName + "失败!");
+ return false;
+ }
+ } else {
+ System.out.println("删除单个文件失败:" + fileName + "不存在!");
+ return false;
+ }
+ }
+
+ /**
+ * 删除目录及目录下的文件
+ *
+ * @param dir
+ * 要删除的目录的文件路径
+ * @return 目录删除成功返回true,否则返回false
+ */
+ public static boolean deleteDirectory(String dir) {
+ // 如果dir不以文件分隔符结尾,自动添加文件分隔符
+ if (!dir.endsWith(File.separator))
+ dir = dir + File.separator;
+ File dirFile = new File(dir);
+ // 如果dir对应的文件不存在,或者不是一个目录,则退出
+ if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
+ System.out.println("删除目录失败:" + dir + "不存在!");
+ return false;
+ }
+ boolean flag = true;
+ // 删除文件夹中的所有文件包括子目录
+ File[] files = dirFile.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ // 删除子文件
+ if (files[i].isFile()) {
+ flag = DeleteFileUtil.deleteFile(files[i].getAbsolutePath());
+ if (!flag)
+ break;
+ }
+ // 删除子目录
+ else if (files[i].isDirectory()) {
+ flag = DeleteFileUtil.deleteDirectory(files[i]
+ .getAbsolutePath());
+ if (!flag)
+ break;
+ }
+ }
+ if (!flag) {
+ System.out.println("删除目录失败!");
+ return false;
+ }
+ // 删除当前目录
+ if (dirFile.delete()) {
+ System.out.println("删除目录" + dir + "成功!");
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+/* public static void main(String[] args) {
+// // 删除单个文件
+// String file = "c:/test/test.txt";
+// DeleteFileUtil.deleteFile(file);
+// System.out.println();
+ // 删除一个目录
+ String dir = "E:/template/20190509222628.zip";
+// DeleteFileUtil.deleteDirectory(dir);
+ deleteFile(dir);
+// System.out.println();
+// // 删除文件
+// dir = "c:/test/test0";
+// DeleteFileUtil.delete(dir);
+
+ }*/
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
index 8459e1478..c4d25e480 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
@@ -54,9 +54,9 @@ public class ExcelUtil {
* @param isValidate 是否 Validator 检验 默认为是
* @return 转换后集合
*/
- public static ExcelResult importExcel(InputStream is, Class clazz, boolean isValidate) {
+ public static ExcelResult importExcel(InputStream is, Class clazz, boolean isValidate,Integer num) {
DefaultExcelListener listener = new DefaultExcelListener<>(isValidate);
- EasyExcel.read(is, clazz, listener).sheet().doRead();
+ EasyExcel.read(is, clazz, listener).sheet().headRowNumber(num).doRead();
return listener.getExcelResult();
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExportWordUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExportWordUtil.java
new file mode 100644
index 000000000..c61404002
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExportWordUtil.java
@@ -0,0 +1,138 @@
+package com.ruoyi.common.utils.poi;
+
+import com.deepoove.poi.XWPFTemplate;
+import com.deepoove.poi.config.Configure;
+import com.deepoove.poi.util.PoitlIOUtils;
+import org.springframework.util.Assert;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+/**
+ * word模板导出
+ * @author ljl
+ */
+public class ExportWordUtil {
+ private ExportWordUtil() {
+ }
+
+ /**
+ * 1.compile 编译模板
+ * 2.render 渲染数据
+ * 3.输出到流
+ * @param hashMap
+ */
+ public static String createWord(String templatePath, String fileDir, String fileName, Map hashMap ){
+ Assert.notNull(templatePath, "word模板文件路径不能为空");
+ Assert.notNull(fileDir, "生成的文件存放地址不能为空");
+ Assert.notNull(fileName, "生成的文件名不能为空");
+
+ // 生成的word格式
+ String formatSuffix = ".docx";
+ // 拼接后的文件名
+ fileName = fileName + formatSuffix;
+
+ // 生成的文件的存放路径
+ if (!fileDir.endsWith("/")) {
+ fileDir = fileDir + File.separator;
+ }
+
+ File dir = new File(fileDir);
+ if (!dir.exists()) {
+ System.out.println("生成word数据时存储文件目录{}不存在,为您创建文件夹!");
+ dir.mkdirs();
+ }
+
+ String filePath = fileDir + fileName;
+ // 读取模板templatePath并将paramMap的内容填充进模板,即编辑模板+渲染数据
+ XWPFTemplate template = XWPFTemplate.compile(templatePath).render(hashMap);
+ try {
+ // 将填充之后的模板写入filePath
+ template.writeToFile(filePath);
+ template.close();
+ } catch (Exception e) {
+ System.out.println("生成word异常");
+ e.printStackTrace();
+ return "";
+ }
+ return filePath;
+ }
+
+ /**
+ * 输出到网络中
+ * @param response
+ * @param templatePath
+ * @param fileName
+ * @param hashMap
+ * @return
+ */
+ public static String createWord(HttpServletResponse response, String templatePath, String fileName, Map hashMap){
+ Assert.notNull(templatePath, "word模板文件路径不能为空");
+ //Assert.notNull(fileDir, "生成的文件存放地址不能为空");
+ Assert.notNull(fileName, "生成的文件名不能为空");
+ // 生成的word格式
+ String formatSuffix = ".docx";
+ // 拼接后的文件名
+// fileName = fileName + formatSuffix;
+ // 读取模板templatePath并将paramMap的内容填充进模板,即编辑模板+渲染数据
+ XWPFTemplate template = XWPFTemplate.compile(templatePath).render(hashMap);
+ try {
+ response.reset();
+ response.setCharacterEncoding("UTF-8");
+// response.setContentType("application/msword");
+ response.setContentType("application/octet-stream");
+ response.setHeader("Content-disposition","attachment;filename="+new String(fileName.getBytes(StandardCharsets.UTF_8),StandardCharsets.ISO_8859_1));
+ OutputStream out = response.getOutputStream();
+ // 将填充之后的模板写入filePath
+// template.write(out);
+// out.flush();
+// template.close();
+ // HttpServletResponse response
+ BufferedOutputStream bos = new BufferedOutputStream(out);
+
+ template.write(bos);
+ bos.flush();
+ out.flush();
+ PoitlIOUtils.closeQuietlyMulti(template, bos, out);
+ } catch (Exception e) {
+ System.out.println("生成word异常");
+ e.printStackTrace();
+ return "";
+ }
+ return fileName;
+ }
+
+
+ public static String createWord1(HttpServletResponse response, HttpServletRequest request, String templatePath, String fileName, Map hashMap, Configure configure){
+ Assert.notNull(templatePath, "word模板文件路径不能为空");
+ //Assert.notNull(fileDir, "生成的文件存放地址不能为空");
+ Assert.notNull(fileName, "生成的文件名不能为空");
+ // 生成的word格式
+ String formatSuffix = ".docx";
+ // 拼接后的文件名
+ //fileName = fileName + formatSuffix;
+ // 读取模板templatePath并将paramMap的内容填充进模板,即编辑模板+渲染数据
+ XWPFTemplate template = XWPFTemplate.compile(templatePath,configure).render(hashMap);
+ try {
+ response.setCharacterEncoding("UTF-8");
+ response.setContentType("application/octet-stream");
+ response.setHeader("Content-disposition","attachment;filename="+new String(fileName.getBytes(StandardCharsets.UTF_8),StandardCharsets.ISO_8859_1));
+ //OutputStream out = response.getOutputStream();
+ OutputStream out = response.getOutputStream();
+ //BufferedOutputStream bos = new BufferedOutputStream(out);
+ // 将填充之后的模板写入filePath
+ template.write(out);
+ template.close();
+ } catch (Exception e) {
+ System.out.println("生成word异常");
+ e.printStackTrace();
+ return "";
+ }
+ return fileName;
+ }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ZipUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ZipUtils.java
new file mode 100644
index 000000000..73ed2d377
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ZipUtils.java
@@ -0,0 +1,132 @@
+package com.ruoyi.common.utils.poi;
+
+import java.io.*;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+
+public class ZipUtils {
+ private static final int BUFFER_SIZE = 2 * 1024;
+
+
+ public static void toZip(String srcDir, String out, boolean KeepDirStructure)
+ throws RuntimeException {
+ long start = System.currentTimeMillis();
+ ZipOutputStream zos = null;
+ try {
+ FileOutputStream fos1 = new FileOutputStream(new File(out));
+ zos = new ZipOutputStream(fos1);
+ File sourceFile = new File(srcDir);
+ compress(sourceFile, zos, sourceFile.getName(), KeepDirStructure);
+ long end = System.currentTimeMillis();
+ System.out.println("压缩完成,耗时:" + (end - start) + " ms");
+ } catch (Exception e) {
+ throw new RuntimeException("zip error from ZipUtils", e);
+ } finally {
+ if (zos != null) {
+ try {
+ zos.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ }
+
+
+ public static void toZip(List srcFiles, OutputStream out) throws RuntimeException {
+ long start = System.currentTimeMillis();
+ ZipOutputStream zos = null;
+ try {
+ zos = new ZipOutputStream(out);
+ for (File srcFile : srcFiles) {
+ byte[] buf = new byte[BUFFER_SIZE];
+ zos.putNextEntry(new ZipEntry(srcFile.getName()));
+ int len;
+ FileInputStream in = new FileInputStream(srcFile);
+ while ((len = in.read(buf)) != -1) {
+ zos.write(buf, 0, len);
+ }
+ zos.closeEntry();
+ in.close();
+ }
+ long end = System.currentTimeMillis();
+ System.out.println("压缩完成,耗时:" + (end - start) + " ms");
+ } catch (Exception e) {
+ throw new RuntimeException("zip error from ZipUtils", e);
+ } finally {
+ if (zos != null) {
+ try {
+ zos.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+
+
+ public static void compress(File sourceFile, ZipOutputStream zos, String name,
+ boolean KeepDirStructure) throws Exception {
+ byte[] buf = new byte[BUFFER_SIZE];
+ if (sourceFile.isFile()) {
+ // 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
+ zos.putNextEntry(new ZipEntry(name));
+ // copy文件到zip输出流中
+ int len;
+ FileInputStream in = new FileInputStream(sourceFile);
+ while ((len = in.read(buf)) != -1) {
+ zos.write(buf, 0, len);
+ }
+ zos.closeEntry();
+ in.close();
+ } else {
+ File[] listFiles = sourceFile.listFiles();
+ if (listFiles == null || listFiles.length == 0) {
+ // 需要保留原来的文件结构时,需要对空文件夹进行处理
+ if (KeepDirStructure) {
+ // 空文件夹的处理
+ zos.putNextEntry(new ZipEntry(name + "/"));
+ // 没有文件,不需要文件的copy
+ zos.closeEntry();
+ }
+ } else {
+ for (File file : listFiles) {
+ // 判断是否需要保留原来的文件结构
+ if (KeepDirStructure) {
+ // 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
+ // 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
+ compress(file, zos, name + "/" + file.getName(), KeepDirStructure);
+ } else {
+ compress(file, zos, file.getName(), KeepDirStructure);
+ }
+ }
+ }
+ }
+ }
+
+
+ public static void main(String[] args) throws Exception {
+
+// FileOutputStream fos1 = new FileOutputStream(new File("H:/mytest01.zip"));
+// ZipUtils.toZip("H:/a", fos1, true);
+
+// List fileList = new ArrayList<>();
+//// fileList.add(new File("H:/1.png"));
+// fileList.add(new File("E:/a"));
+// FileOutputStream fos2 = new FileOutputStream(new File("H:/123.zip"));
+// ZipUtils.toZip(fileList, fos2);
+// DocumentHandler documentHandler = new DocumentHandler();
+// String str = "http://192.168.0.66:8090/file/d4d076edcfc34415ae0e4296fd8dc035.png";
+//// String[] split = str.split(".");
+// String n1=str.substring(str.lastIndexOf("."));
+// System.out.println(n1);
+//// documentHandler.download(str, "aaaa"+split[split.length - 1]);
+
+ }
+
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/Seq.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/Seq.java
new file mode 100644
index 000000000..8ddc4089d
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/Seq.java
@@ -0,0 +1,86 @@
+package com.ruoyi.common.utils.uuid;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * @author ruoyi 序列生成类
+ */
+public class Seq
+{
+ // 通用序列类型
+ public static final String commSeqType = "COMMON";
+
+ // 上传序列类型
+ public static final String uploadSeqType = "UPLOAD";
+
+ // 通用接口序列数
+ private static AtomicInteger commSeq = new AtomicInteger(1);
+
+ // 上传接口序列数
+ private static AtomicInteger uploadSeq = new AtomicInteger(1);
+
+ // 机器标识
+ private static final String machineCode = "A";
+
+ /**
+ * 获取通用序列号
+ *
+ * @return 序列值
+ */
+ public static String getId()
+ {
+ return getId(commSeqType);
+ }
+
+ /**
+ * 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
+ *
+ * @return 序列值
+ */
+ public static String getId(String type)
+ {
+ AtomicInteger atomicInt = commSeq;
+ if (uploadSeqType.equals(type))
+ {
+ atomicInt = uploadSeq;
+ }
+ return getId(atomicInt, 3);
+ }
+
+ /**
+ * 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
+ *
+ * @param atomicInt 序列数
+ * @param length 数值长度
+ * @return 序列值
+ */
+ public static String getId(AtomicInteger atomicInt, int length)
+ {
+ String result = DateUtils.dateTimeNow();
+ result += machineCode;
+ result += getSeq(atomicInt, length);
+ return result;
+ }
+
+ /**
+ * 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数
+ *
+ * @return 序列值
+ */
+ private synchronized static String getSeq(AtomicInteger atomicInt, int length)
+ {
+ // 先取值再+1
+ int value = atomicInt.getAndIncrement();
+
+ // 如果更新后值>=10 的 (length)幂次方则重置为1
+ int maxSeq = (int) Math.pow(10, length);
+ if (atomicInt.get() >= maxSeq)
+ {
+ atomicInt.set(1);
+ }
+ // 转字符串,用0左补齐
+ return StringUtils.padl(value, length);
+ }
+}
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java
index 873facc3b..ea3a0d3d3 100644
--- a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java
@@ -74,7 +74,7 @@ public class TestDemoController extends BaseController {
@SaCheckPermission("demo:demo:import")
@PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R importData(@RequestPart("file") MultipartFile file) throws Exception {
- ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), TestDemoImportVo.class, true);
+ ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), TestDemoImportVo.class, true,0);
List volist = excelResult.getList();
List list = BeanUtil.copyToList(volist, TestDemo.class);
iTestDemoService.saveBatch(list);
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/ImageDemoData.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/ImageDemoData.java
new file mode 100644
index 000000000..5554aa95b
--- /dev/null
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/ImageDemoData.java
@@ -0,0 +1,43 @@
+package com.ruoyi.demo.domain;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import com.alibaba.excel.annotation.write.style.ContentRowHeight;
+import com.alibaba.excel.converters.string.StringImageConverter;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+
+@Getter
+@Setter
+@EqualsAndHashCode
+@ContentRowHeight(100)
+@ColumnWidth(100 / 8)
+public class ImageDemoData {
+ private File file;
+ private InputStream inputStream;
+ /**
+ * 如果string类型 必须指定转换器,string默认转换成string
+ */
+ @ExcelProperty(converter = StringImageConverter.class)
+ private String string;
+ private byte[] byteArray;
+ /**
+ * 根据url导出
+ *
+ * @since 2.1.1
+ */
+ private URL url;
+
+ /**
+ * 根据文件导出 并设置导出的位置。
+ *
+ * @since 3.0.0-beta1
+ */
+ private WriteCellData writeCellDataFile;
+}
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestDemo.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestDemo.java
index dc19ce2c7..c9f3f81b4 100644
--- a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestDemo.java
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestDemo.java
@@ -22,7 +22,7 @@ public class TestDemo extends BaseEntity {
/**
* 主键
*/
- @TableId(value = "id")
+ @TableId(value = "id",type = IdType.AUTO)
private Long id;
/**
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestTree.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestTree.java
index b480aa0c1..bd056fdf8 100644
--- a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestTree.java
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestTree.java
@@ -1,9 +1,6 @@
package com.ruoyi.demo.domain;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableLogic;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.baomidou.mybatisplus.annotation.Version;
+import com.baomidou.mybatisplus.annotation.*;
import com.ruoyi.common.core.domain.TreeEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -25,7 +22,7 @@ public class TestTree extends TreeEntity {
/**
* 主键
*/
- @TableId(value = "id")
+ @TableId(value = "id",type = IdType.AUTO)
private Long id;
/**
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/init/RedisDelayQueueHandle.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/init/RedisDelayQueueHandle.java
new file mode 100644
index 000000000..9dd3268ca
--- /dev/null
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/init/RedisDelayQueueHandle.java
@@ -0,0 +1,11 @@
+package com.ruoyi.demo.init;
+
+/**
+ * 延迟队列执行器
+ * Created by LPB on 2021/04/20.
+ */
+public interface RedisDelayQueueHandle {
+
+ void execute(T t);
+
+}
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/init/RedisDelayQueueRunner.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/init/RedisDelayQueueRunner.java
new file mode 100644
index 000000000..99dc87d56
--- /dev/null
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/init/RedisDelayQueueRunner.java
@@ -0,0 +1,57 @@
+package com.ruoyi.demo.init;/*
+package cn.dbtalents.checktalents.init;
+import cn.dbtalents.checktalents.enums.RedisDelayQueueEnum;
+import cn.dbtalents.checktalents.handle.RedisDelayQueueHandle;
+import cn.dbtalents.checktalents.util.RedisDelayQueueUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Component;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+*/
+/**
+ * 启动延迟队列
+ *//*
+
+@Slf4j
+@Component
+public class RedisDelayQueueRunner implements CommandLineRunner {
+
+ @Autowired
+ private RedisDelayQueueUtil redisDelayQueueUtil;
+ */
+/* @Autowired
+ private ThreadPoolTaskExecutor threadPool;
+ ThreadPoolExecutor executorService = new ThreadPoolExecutor(10, 50, 30, TimeUnit.SECONDS,
+ new LinkedBlockingQueue(1000), Executors.defaultThreadFactory());*//*
+
+ @Override
+ public void run(String... args) {
+ */
+/* threadPool.execute(() -> {
+ while (true){*//*
+
+ try {
+ RedisDelayQueueEnum[] queueEnums = RedisDelayQueueEnum.values();
+ for (RedisDelayQueueEnum queueEnum : queueEnums) {
+ Object value = redisDelayQueueUtil.getDelayQueue(queueEnum.getCode());
+ if (value != null) {
+ RedisDelayQueueHandle redisDelayQueueHandle = SpringUtil.getBean(queueEnum.getBeanId());
+ redisDelayQueueHandle.execute(value);
+ }
+ }
+ } catch (InterruptedException e) {
+ log.error("(Redis延迟队列异常中断) {}", e.getMessage());
+ }
+// }
+// });
+ log.info("(Redis延迟队列启动成功)");
+ }
+}
+*/
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/init/RedisDelayedQueueInit.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/init/RedisDelayedQueueInit.java
new file mode 100644
index 000000000..51a7242d8
--- /dev/null
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/init/RedisDelayedQueueInit.java
@@ -0,0 +1,60 @@
+package com.ruoyi.demo.init;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RBlockingQueue;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+import java.util.Map;
+
+/**
+ * redis 延时队列初始化
+ */
+@Component
+@Slf4j
+public class RedisDelayedQueueInit implements ApplicationContextAware {
+
+ @Autowired
+ private RedissonClient redissonClient;
+
+ /**
+ * 获取应用上下文并获取相应的接口实现类
+ * @param applicationContext
+ * @throws BeansException
+ */
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ Map map = applicationContext.getBeansOfType(RedisDelayQueueHandle.class);
+ for (Map.Entry taskEventListenerEntry : map.entrySet()) {
+ String listenerName = taskEventListenerEntry.getValue().getClass().getName();
+ startThread(listenerName, taskEventListenerEntry.getValue());
+ }
+ }
+
+ /**
+ * 启动线程获取队列
+ * @param queueName 队列名称
+ * @param redisDelayedQueueListener 任务回调监听
+ */
+ private void startThread(String queueName, RedisDelayQueueHandle redisDelayedQueueListener) {
+ RBlockingQueue blockingFairQueue = redissonClient.getBlockingQueue(queueName);
+ //由于此线程需要常驻,可以新建线程,不用交给线程池管理
+ Thread thread = new Thread(() -> {
+ log.info("启动监听队列线程" + queueName);
+ while (true) {
+ try {
+ T t = blockingFairQueue.take();
+ log.info("监听队列线程{},获取到值:{}", queueName, t);
+ redisDelayedQueueListener.execute(t);
+ } catch (Exception e) {
+ log.info("监听队列线程错误,", e);
+ }
+ }
+ });
+ thread.setName(queueName);
+ thread.start();
+ log.info("(Redis延迟队列启动成功)");
+ }
+}
diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml
index 1b729ef1b..a66dada79 100644
--- a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml
+++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml
@@ -41,5 +41,5 @@ spring.boot.admin.client:
url: http://localhost:9090/admin
instance:
service-host-type: IP
- username: ruoyi
- password: 123456
+ username: gaoxin
+ password: 1234Qwer@
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java
index 0be6ba663..7bacf3080 100644
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java
@@ -25,4 +25,4 @@ public class WebMvcConfig implements WebMvcConfigurer {
registry.addInterceptor(cookieInterceptor).addPathPatterns("/**");
}
-}
\ No newline at end of file
+}
diff --git a/ruoyi-file/pom.xml b/ruoyi-file/pom.xml
new file mode 100644
index 000000000..6a99cc729
--- /dev/null
+++ b/ruoyi-file/pom.xml
@@ -0,0 +1,35 @@
+
+
+
+ ruoyi-vue-plus
+ com.ruoyi
+ 4.8.0
+
+ 4.0.0
+
+ ruoyi-file
+
+
+ 文件存放模块
+
+
+
+
+
+
+ com.ruoyi
+ ruoyi-common
+
+
+
+
+
+
+
+
diff --git a/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java b/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java
new file mode 100644
index 000000000..51009defa
--- /dev/null
+++ b/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java
@@ -0,0 +1,94 @@
+/*
+package com.ruoyi.file.config;
+
+import io.minio.MinioClient;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+*/
+/**
+ * Minio 配置信息
+ *
+ * @author ruoyi
+ *//*
+
+@Configuration
+@ConfigurationProperties(prefix = "minio")
+public class MinioConfig
+{
+ */
+/**
+ * 服务地址
+ *//*
+
+ private String url;
+
+ */
+/**
+ * 用户名
+ *//*
+
+ private String accessKey;
+
+ */
+/**
+ * 密码
+ *//*
+
+ private String secretKey;
+
+ */
+/**
+ * 存储桶名称
+ *//*
+
+ private String bucketName;
+
+ public String getUrl()
+ {
+ return url;
+ }
+
+ public void setUrl(String url)
+ {
+ this.url = url;
+ }
+
+ public String getAccessKey()
+ {
+ return accessKey;
+ }
+
+ public void setAccessKey(String accessKey)
+ {
+ this.accessKey = accessKey;
+ }
+
+ public String getSecretKey()
+ {
+ return secretKey;
+ }
+
+ public void setSecretKey(String secretKey)
+ {
+ this.secretKey = secretKey;
+ }
+
+ public String getBucketName()
+ {
+ return bucketName;
+ }
+
+ public void setBucketName(String bucketName)
+ {
+ this.bucketName = bucketName;
+ }
+
+ @Bean
+ public MinioClient getMinioClient()
+ {
+ return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
+ }
+}
+*/
diff --git a/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java b/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java
new file mode 100644
index 000000000..b4e99f4c7
--- /dev/null
+++ b/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java
@@ -0,0 +1,62 @@
+/*
+package com.ruoyi.file.config;
+
+import java.io.File;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+*/
+/**
+ * 通用映射配置
+ *
+ * @author ruoyi
+ *//*
+
+@Configuration
+public class ResourcesConfig implements WebMvcConfigurer
+{
+ */
+/**
+ * 上传文件存储在本地的根路径
+ *//*
+
+ @Value("${file.path}")
+ private String localFilePath;
+
+ */
+/**
+ * 资源映射路径 前缀
+ *//*
+
+ @Value("${file.prefix}")
+ public String localFilePrefix;
+
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry)
+ {
+ */
+/** 本地文件上传路径 *//*
+
+ registry.addResourceHandler(localFilePrefix + "/**")
+ .addResourceLocations("file:" + localFilePath + File.separator);
+ }
+
+ */
+/**
+ * 开启跨域
+ *//*
+
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ // 设置允许跨域的路由
+ registry.addMapping(localFilePrefix + "/**")
+ // 设置允许跨域请求的域名
+ .allowedOrigins("*")
+ // 设置允许的方法
+ .allowedMethods("GET");
+ }
+}
+*/
diff --git a/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsSysFileServiceImpl.java b/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsSysFileServiceImpl.java
new file mode 100644
index 000000000..9743cf374
--- /dev/null
+++ b/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsSysFileServiceImpl.java
@@ -0,0 +1,53 @@
+/*
+package com.ruoyi.file.service;
+
+import java.io.InputStream;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+import com.github.tobato.fastdfs.domain.fdfs.StorePath;
+import com.github.tobato.fastdfs.service.FastFileStorageClient;
+import com.ruoyi.common.core.utils.file.FileTypeUtils;
+
+*/
+/**
+ * FastDFS 文件存储
+ *
+ * @author ruoyi
+ *//*
+
+@Service
+public class FastDfsSysFileServiceImpl implements ISysFileService
+{
+ */
+/**
+ * 域名或本机访问地址
+ *//*
+
+ @Value("${fdfs.domain}")
+ public String domain;
+
+ @Autowired
+ private FastFileStorageClient storageClient;
+
+ */
+/**
+ * FastDfs文件上传接口
+ *
+ * @param file 上传的文件
+ * @return 访问地址
+ * @throws Exception
+ *//*
+
+ @Override
+ public String uploadFile(MultipartFile file) throws Exception
+ {
+ InputStream inputStream = file.getInputStream();
+ StorePath storePath = storageClient.uploadFile(inputStream, file.getSize(),
+ FileTypeUtils.getExtension(file), null);
+ inputStream.close();
+ return domain + "/" + storePath.getFullPath();
+ }
+}
+*/
diff --git a/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java b/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java
new file mode 100644
index 000000000..472ad5b40
--- /dev/null
+++ b/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java
@@ -0,0 +1,20 @@
+package com.ruoyi.file.service;
+
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * 文件上传接口
+ *
+ * @author ruoyi
+ */
+public interface ISysFileService
+{
+ /**
+ * 文件上传接口
+ *
+ * @param file 上传的文件
+ * @return 访问地址
+ * @throws Exception
+ */
+ public String uploadFile(MultipartFile file) throws Exception;
+}
diff --git a/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java b/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java
new file mode 100644
index 000000000..1a2fe2104
--- /dev/null
+++ b/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java
@@ -0,0 +1,53 @@
+package com.ruoyi.file.service;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.file.utils.FileUploadUtils;
+
+/**
+ * 本地文件存储
+ *
+ * @author ruoyi
+ */
+@Primary
+@Service
+public class LocalSysFileServiceImpl implements ISysFileService
+{
+
+ /**
+ * 资源映射路径 前缀
+ */
+ @Value("${file.prefix}")
+ public String localFilePrefix;
+
+ /**
+ * 域名或本机访问地址
+ */
+ @Value("${file.domain}")
+ public String domain;
+
+ /**
+ * 上传文件存储在本地的根路径
+ */
+ @Value("${file.path}")
+ private String localFilePath;
+
+
+
+ /**
+ * 本地文件上传接口
+ *
+ * @param file 上传的文件
+ * @return 访问地址
+ * @throws Exception
+ */
+ @Override
+ public String uploadFile(MultipartFile file) throws Exception
+ {
+ String name = FileUploadUtils.upload(localFilePath, file);
+ String url = domain + localFilePrefix + name;
+ return url;
+ }
+}
diff --git a/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java b/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java
new file mode 100644
index 000000000..33e3b3c39
--- /dev/null
+++ b/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java
@@ -0,0 +1,54 @@
+/*
+package com.ruoyi.file.service;
+
+import java.io.InputStream;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.file.config.MinioConfig;
+import com.ruoyi.file.utils.FileUploadUtils;
+import io.minio.MinioClient;
+import io.minio.PutObjectArgs;
+
+*/
+/**
+ * Minio 文件存储
+ *
+ * @author ruoyi
+ *//*
+
+@Service
+public class MinioSysFileServiceImpl implements ISysFileService
+{
+ @Autowired
+ private MinioConfig minioConfig;
+
+ @Autowired
+ private MinioClient client;
+
+ */
+/**
+ * Minio文件上传接口
+ *
+ * @param file 上传的文件
+ * @return 访问地址
+ * @throws Exception
+ *//*
+
+ @Override
+ public String uploadFile(MultipartFile file) throws Exception
+ {
+ String fileName = FileUploadUtils.extractFilename(file);
+ InputStream inputStream = file.getInputStream();
+ PutObjectArgs args = PutObjectArgs.builder()
+ .bucket(minioConfig.getBucketName())
+ .object(fileName)
+ .stream(inputStream, file.getSize(), -1)
+ .contentType(file.getContentType())
+ .build();
+ client.putObject(args);
+ inputStream.close();
+ return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
+ }
+}
+*/
diff --git a/ruoyi-file/src/main/java/com/ruoyi/file/utils/FileUploadUtils.java b/ruoyi-file/src/main/java/com/ruoyi/file/utils/FileUploadUtils.java
new file mode 100644
index 000000000..c5aa14c7a
--- /dev/null
+++ b/ruoyi-file/src/main/java/com/ruoyi/file/utils/FileUploadUtils.java
@@ -0,0 +1,183 @@
+package com.ruoyi.file.utils;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.Objects;
+
+import com.ruoyi.common.exception.file.FileException;
+import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException;
+import com.ruoyi.common.exception.file.FileSizeLimitExceededException;
+import com.ruoyi.common.exception.file.InvalidExtensionException;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.file.FileTypeUtils;
+import com.ruoyi.common.utils.file.MimeTypeUtils;
+import com.ruoyi.common.utils.uuid.Seq;
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * 文件上传工具类
+ *
+ * @author ruoyi
+ */
+public class FileUploadUtils
+{
+ /**
+ * 默认大小 50M
+ */
+ public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
+
+ /**
+ * 默认的文件名最大长度 100
+ */
+ public static final int DEFAULT_FILE_NAME_LENGTH = 100;
+
+ /**
+ * 根据文件路径上传
+ *
+ * @param baseDir 相对应用的基目录
+ * @param file 上传的文件
+ * @return 文件名称
+ * @throws IOException
+ */
+ public static final String upload(String baseDir, MultipartFile file) throws IOException
+ {
+ try
+ {
+ return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
+ }
+ catch (FileException fe)
+ {
+ throw new IOException(fe.getDefaultMessage(), fe);
+ }
+ catch (Exception e)
+ {
+ throw new IOException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * 文件上传
+ *
+ * @param baseDir 相对应用的基目录
+ * @param file 上传的文件
+ * @param allowedExtension 上传文件类型
+ * @return 返回上传成功的文件名
+ * @throws FileSizeLimitExceededException 如果超出最大大小
+ * @throws FileNameLengthLimitExceededException 文件名太长
+ * @throws IOException 比如读写文件出错时
+ * @throws
+ */
+ public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
+ throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException {
+ int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
+ if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
+ {
+ throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
+ }
+
+ assertAllowed(file, allowedExtension);
+
+ String fileName = extractFilename(file);
+
+ String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
+ file.transferTo(Paths.get(absPath));
+ return getPathFileName(fileName);
+ }
+
+ /**
+ * 编码文件名
+ */
+ public static final String extractFilename(MultipartFile file)
+ {
+ return StringUtils.format("{}/{}.{}", DateUtils.datePath(),
+ Seq.getId(Seq.uploadSeqType), FileTypeUtils.getExtension(file));
+ }
+
+ private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
+ {
+ File desc = new File(uploadDir + File.separator + fileName);
+
+ if (!desc.exists())
+ {
+ if (!desc.getParentFile().exists())
+ {
+ desc.getParentFile().mkdirs();
+ }
+ }
+ return desc.isAbsolute() ? desc : desc.getAbsoluteFile();
+ }
+
+ private static final String getPathFileName(String fileName) throws IOException
+ {
+ String pathFileName = "/" + fileName;
+ return pathFileName;
+ }
+
+ /**
+ * 文件大小校验
+ *
+ * @param file 上传的文件
+ * @throws FileSizeLimitExceededException 如果超出最大大小
+ * @throws InvalidExtensionException 文件校验异常
+ */
+ public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
+ throws FileSizeLimitExceededException, InvalidExtensionException {
+ long size = file.getSize();
+ if (size > DEFAULT_MAX_SIZE)
+ {
+ throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
+ }
+
+ String fileName = file.getOriginalFilename();
+ String extension = FileTypeUtils.getExtension(file);
+ if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
+ {
+ if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
+ {
+ throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
+ fileName);
+ }
+ else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
+ {
+ throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
+ fileName);
+ }
+ else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
+ {
+ throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
+ fileName);
+ }
+ else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
+ {
+ throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
+ fileName);
+ }
+ else
+ {
+ throw new InvalidExtensionException(allowedExtension, extension, fileName);
+ }
+ }
+ }
+
+ /**
+ * 判断MIME类型是否是允许的MIME类型
+ *
+ * @param extension 上传文件类型
+ * @param allowedExtension 允许上传文件类型
+ * @return true/false
+ */
+ public static final boolean isAllowedExtension(String extension, String[] allowedExtension)
+ {
+ for (String str : allowedExtension)
+ {
+ if (str.equalsIgnoreCase(extension))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
index a9d61fb60..f365e6344 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
@@ -5,6 +5,7 @@ import com.ruoyi.common.annotation.RateLimiter;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.enums.LimitType;
import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
@@ -120,7 +121,10 @@ public class RateLimiterAspect {
if (rateLimiter.limitType() == LimitType.IP) {
// 获取请求ip
stringBuffer.append(ServletUtils.getClientIP()).append(":");
- } else if (rateLimiter.limitType() == LimitType.CLUSTER) {
+ }else if (rateLimiter.limitType() == LimitType.USERID){
+ // 获取用户ID
+ stringBuffer.append(String.valueOf(LoginHelper.getUserId())).append(":");
+ }else if (rateLimiter.limitType() == LimitType.CLUSTER) {
// 获取客户端实例id
stringBuffer.append(RedisUtils.getClient().getId()).append(":");
}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
index ea83338ba..ceb1de4fb 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
@@ -1,15 +1,20 @@
package com.ruoyi.framework.config;
import com.ruoyi.framework.interceptor.PlusWebInvokeTimeInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import java.io.File;
+
/**
* 通用配置
*
@@ -18,15 +23,22 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class ResourcesConfig implements WebMvcConfigurer {
+ @Value("${file.path}")
+ private String localFilePath;
+
+ /**
+ * 资源映射路径 前缀
+ */
+ @Value("${file.prefix}")
+ public String localFilePrefix;
+
+
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 全局访问性能拦截
registry.addInterceptor(new PlusWebInvokeTimeInterceptor());
}
- @Override
- public void addResourceHandlers(ResourceHandlerRegistry registry) {
- }
/**
* 跨域配置
@@ -49,4 +61,29 @@ public class ResourcesConfig implements WebMvcConfigurer {
// 返回新的CorsFilter
return new CorsFilter(source);
}
+ /**
+ * 上传文件存储在本地的根路径
+ */
+
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry)
+ {
+ /** 本地文件上传路径 */
+ registry.addResourceHandler(localFilePrefix + "/**")
+ .addResourceLocations("file:" + localFilePath + File.separator);
+ }
+
+ /**
+ * 开启跨域
+ */
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ // 设置允许跨域的路由
+ registry.addMapping(localFilePrefix + "/**")
+ .allowedOrigins("*")
+ .allowCredentials(true)
+ .maxAge(3000)
+ // 设置允许的方法
+ .allowedMethods("GET");
+ }
}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/PlusWebInvokeTimeInterceptor.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/PlusWebInvokeTimeInterceptor.java
index 78bffab4f..71498ed14 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/PlusWebInvokeTimeInterceptor.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/PlusWebInvokeTimeInterceptor.java
@@ -3,6 +3,7 @@ package com.ruoyi.framework.interceptor;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import com.alibaba.ttl.TransmittableThreadLocal;
+import com.ruoyi.common.core.service.ConfigService;
import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.StringUtils;
@@ -34,6 +35,7 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+// response.sendRedirect("https://dbxqtalents.cn/");
if (!prodProfile.equals(SpringUtils.getActiveProfile())) {
String url = request.getMethod() + " " + request.getRequestURI();
@@ -59,6 +61,10 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
invokeTimeTL.set(stopWatch);
stopWatch.start();
}
+ //判断系统是否在维护中
+ ConfigService sysConfigService = SpringUtils.getBean(ConfigService.class);
+ //系统升级提示
+ sysConfigService.selectConfigByConfigKey("system:maintenance:prompt");
return true;
}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/listener/UserActionListener.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/listener/UserActionListener.java
index a9de17e60..8ad8828bd 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/listener/UserActionListener.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/listener/UserActionListener.java
@@ -58,6 +58,23 @@ public class UserActionListener implements SaTokenListener {
log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue);
} else if (userType == UserType.APP_USER) {
// app端 自行根据业务编写
+ UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
+ String ip = ServletUtils.getClientIP();
+ LoginUser user = LoginHelper.getLoginUser();
+ UserOnlineDTO dto = new UserOnlineDTO();
+ dto.setIpaddr(ip);
+ dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
+ dto.setBrowser(userAgent.getBrowser().getName());
+ dto.setOs(userAgent.getOs().getName());
+ dto.setLoginTime(System.currentTimeMillis());
+ dto.setTokenId(tokenValue);
+ dto.setUserName(user.getUsername());
+ if(tokenConfig.getTimeout() == -1) {
+ RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto);
+ } else {
+ RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout()));
+ }
+ log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue);
}
}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java
index 45e9168e5..fdde2f247 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java
@@ -26,7 +26,7 @@ public class GenTable extends BaseEntity {
/**
* 编号
*/
- @TableId(value = "table_id")
+ @TableId(value = "table_id",type = IdType.AUTO)
private Long tableId;
/**
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
index f6dbcaaf4..7ade87ae1 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
@@ -1,9 +1,6 @@
package com.ruoyi.generator.domain;
-import com.baomidou.mybatisplus.annotation.FieldStrategy;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.*;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.utils.StringUtils;
import lombok.Data;
@@ -26,7 +23,7 @@ public class GenTableColumn extends BaseEntity {
/**
* 编号
*/
- @TableId(value = "column_id")
+ @TableId(value = "column_id",type = IdType.AUTO)
private Long columnId;
/**
diff --git a/ruoyi-job/src/main/java/com/ruoyi/job/config/XxlJobConfig.java b/ruoyi-job/src/main/java/com/ruoyi/mq/config/XxlJobConfig.java
similarity index 94%
rename from ruoyi-job/src/main/java/com/ruoyi/job/config/XxlJobConfig.java
rename to ruoyi-job/src/main/java/com/ruoyi/mq/config/XxlJobConfig.java
index e051ff0d4..19b25179c 100644
--- a/ruoyi-job/src/main/java/com/ruoyi/job/config/XxlJobConfig.java
+++ b/ruoyi-job/src/main/java/com/ruoyi/mq/config/XxlJobConfig.java
@@ -1,6 +1,5 @@
-package com.ruoyi.job.config;
+package com.ruoyi.mq.config;
-import com.ruoyi.job.config.properties.XxlJobProperties;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
diff --git a/ruoyi-job/src/main/java/com/ruoyi/job/config/properties/XxlJobProperties.java b/ruoyi-job/src/main/java/com/ruoyi/mq/config/XxlJobProperties.java
similarity index 94%
rename from ruoyi-job/src/main/java/com/ruoyi/job/config/properties/XxlJobProperties.java
rename to ruoyi-job/src/main/java/com/ruoyi/mq/config/XxlJobProperties.java
index f2c755a15..173d3132f 100644
--- a/ruoyi-job/src/main/java/com/ruoyi/job/config/properties/XxlJobProperties.java
+++ b/ruoyi-job/src/main/java/com/ruoyi/mq/config/XxlJobProperties.java
@@ -1,4 +1,4 @@
-package com.ruoyi.job.config.properties;
+package com.ruoyi.mq.config;
import lombok.Data;
import lombok.NoArgsConstructor;
diff --git a/ruoyi-job/src/main/java/com/ruoyi/job/service/SampleService.java b/ruoyi-job/src/main/java/com/ruoyi/mq/service/SampleService.java
similarity index 99%
rename from ruoyi-job/src/main/java/com/ruoyi/job/service/SampleService.java
rename to ruoyi-job/src/main/java/com/ruoyi/mq/service/SampleService.java
index 4ca170be7..36aa37419 100644
--- a/ruoyi-job/src/main/java/com/ruoyi/job/service/SampleService.java
+++ b/ruoyi-job/src/main/java/com/ruoyi/mq/service/SampleService.java
@@ -1,4 +1,4 @@
-package com.ruoyi.job.service;
+package com.ruoyi.mq.service;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
diff --git a/ruoyi-oss/pom.xml b/ruoyi-oss/pom.xml
index 715eef5c5..8a614fa64 100644
--- a/ruoyi-oss/pom.xml
+++ b/ruoyi-oss/pom.xml
@@ -26,6 +26,12 @@
com.amazonaws
aws-java-sdk-s3
+
+
+ com.google.code.gson
+ gson
+
+
diff --git a/ruoyi-rabbitmq/pom.xml b/ruoyi-rabbitmq/pom.xml
new file mode 100644
index 000000000..917346d38
--- /dev/null
+++ b/ruoyi-rabbitmq/pom.xml
@@ -0,0 +1,34 @@
+
+
+
+ ruoyi-vue-plus
+ com.ruoyi
+ 4.8.0
+
+ 4.0.0
+ jar
+ ruoyi-rabbitmq
+
+
+ 消息队列
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-amqp
+
+
+
+
+
+
diff --git a/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/config/PluginDelayRabbitConfig.java b/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/config/PluginDelayRabbitConfig.java
new file mode 100644
index 000000000..881e3659b
--- /dev/null
+++ b/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/config/PluginDelayRabbitConfig.java
@@ -0,0 +1,44 @@
+package com.ruoyi.mq.config;
+
+import org.springframework.amqp.core.Binding;
+import org.springframework.amqp.core.BindingBuilder;
+import org.springframework.amqp.core.CustomExchange;
+import org.springframework.amqp.core.Queue;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+public class PluginDelayRabbitConfig {
+
+ public static final String PLUGIN_DELAY_EXCHANGE = "pluginDelayExchange";
+ public static final String PLUGIN_DELAY_QUEUE = "pluginDelayQueue";
+ public static final String PLUGIN_DELAY_KEY_TALENTS = "pluginDelayKeyTalents";
+
+ @Bean(PLUGIN_DELAY_EXCHANGE)
+ public CustomExchange pluginDelayExchange() {
+ Map argMap = new HashMap<>();
+ argMap.put("x-delayed-type", "direct");//必须要配置这个类型,可以是direct,topic和fanout
+ //第二个参数必须为x-delayed-message
+ return new CustomExchange(PLUGIN_DELAY_EXCHANGE,"x-delayed-message",true, false, argMap);
+ }
+
+ @Bean(PLUGIN_DELAY_QUEUE)
+ public Queue pluginDelayQueue(){
+ return new Queue(PLUGIN_DELAY_QUEUE,true,false,false);
+ }
+
+ //使用下 ImmediateRequeueMessageRecoverer 重新排队在RabbitMQConfiguration中配置
+ /*@Bean
+ public MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate) {
+ return new RepublishMessageRecoverer(rabbitTemplate,"test_dead_letter_exchange","test_dead_letter_key");
+ }*/
+
+ @Bean("pluginDelayBinding")
+ public Binding pluginDelayBinding(@Qualifier(PLUGIN_DELAY_QUEUE) Queue queue, @Qualifier(PLUGIN_DELAY_EXCHANGE) CustomExchange customExchange){
+ return BindingBuilder.bind(queue).to(customExchange).with(PLUGIN_DELAY_KEY_TALENTS).noargs();
+ }
+}
diff --git a/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/config/RabbitConfig.java b/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/config/RabbitConfig.java
new file mode 100644
index 000000000..98c8acde1
--- /dev/null
+++ b/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/config/RabbitConfig.java
@@ -0,0 +1,50 @@
+package com.ruoyi.mq.config;
+
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+import org.springframework.amqp.rabbit.connection.CorrelationData;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+
+/**
+ * @Author : JCccc
+ * @CreateTime : 2019/9/3
+ * @Description :
+
+**/
+
+@Configuration
+public class RabbitConfig {
+
+ @Bean
+ public RabbitTemplate createRabbitTemplate(ConnectionFactory connectionFactory){
+ RabbitTemplate rabbitTemplate = new RabbitTemplate();
+ rabbitTemplate.setConnectionFactory(connectionFactory);
+ //设置开启Mandatory,才能触发回调函数,无论消息推送结果怎么样都强制调用回调函数
+ rabbitTemplate.setMandatory(true);
+
+ rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
+ @Override
+ public void confirm(CorrelationData correlationData, boolean ack, String cause) {
+ System.out.println("ConfirmCallback: "+"相关数据:"+correlationData);
+ System.out.println("ConfirmCallback: "+"确认情况:"+ack);
+ System.out.println("ConfirmCallback: "+"原因:"+cause);
+ }
+ });
+
+ rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
+ @Override
+ public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
+ System.out.println("ReturnCallback: "+"消息:"+message);
+ System.out.println("ReturnCallback: "+"回应码:"+replyCode);
+ System.out.println("ReturnCallback: "+"回应信息:"+replyText);
+ System.out.println("ReturnCallback: "+"交换机:"+exchange);
+ System.out.println("ReturnCallback: "+"路由键:"+routingKey);
+ }
+ });
+ return rabbitTemplate;
+ }
+
+}
diff --git a/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/config/TalentsDelayRabbitConfig.java b/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/config/TalentsDelayRabbitConfig.java
new file mode 100644
index 000000000..015305f03
--- /dev/null
+++ b/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/config/TalentsDelayRabbitConfig.java
@@ -0,0 +1,46 @@
+package com.ruoyi.mq.config;
+
+import org.springframework.amqp.core.Binding;
+import org.springframework.amqp.core.BindingBuilder;
+import org.springframework.amqp.core.CustomExchange;
+import org.springframework.amqp.core.Queue;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 人才认定消息配置
+ */
+@Configuration
+public class TalentsDelayRabbitConfig {
+ public static final String TALENTS_PLUGIN_DELAY_EXCHANGE = "talentsPluginDelayExchange";
+ public static final String TALENTS_PLUGIN_DELAY_QUEUE = "talentsPluginDelayQueue";
+ public static final String TALENTS_PLUGIN_DELAY_KEY = "talentsPluginDelayKey";
+
+ @Bean(TALENTS_PLUGIN_DELAY_EXCHANGE)
+ public CustomExchange talentsPluginDelayExchange() {
+ Map argMap = new HashMap<>();
+ argMap.put("x-delayed-type", "direct");//必须要配置这个类型,可以是direct,topic和fanout
+ //第二个参数必须为x-delayed-message
+ return new CustomExchange(TALENTS_PLUGIN_DELAY_EXCHANGE,"x-delayed-message",true, false, argMap);
+ }
+
+ @Bean(TALENTS_PLUGIN_DELAY_QUEUE)
+ public Queue talentsPluginDelayQueue(){
+ return new Queue(TALENTS_PLUGIN_DELAY_QUEUE,true,false,false);
+ }
+
+ //使用下 ImmediateRequeueMessageRecoverer 重新排队在RabbitMQConfiguration中配置
+ /*@Bean
+ public MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate) {
+ return new RepublishMessageRecoverer(rabbitTemplate,"test_dead_letter_exchange","test_dead_letter_key");
+ }*/
+
+ @Bean
+ public Binding talentsPluginDelayBinding(@Qualifier(TALENTS_PLUGIN_DELAY_QUEUE) Queue queue, @Qualifier(TALENTS_PLUGIN_DELAY_EXCHANGE) CustomExchange customExchange){
+ return BindingBuilder.bind(queue).to(customExchange).with(TALENTS_PLUGIN_DELAY_KEY).noargs();
+ }
+}
diff --git a/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/service/DirectReceiver.java b/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/service/DirectReceiver.java
new file mode 100644
index 000000000..4b965e492
--- /dev/null
+++ b/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/service/DirectReceiver.java
@@ -0,0 +1,27 @@
+package com.ruoyi.mq.service;
+
+import com.rabbitmq.client.Channel;
+import com.ruoyi.mq.config.TalentsDelayRabbitConfig;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.*;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+@Component
+public class DirectReceiver {
+
+ @RabbitListener(queues = TalentsDelayRabbitConfig.TALENTS_PLUGIN_DELAY_QUEUE)//监听的队列名称 TestDirectQueue
+ public void processs(Message message,Channel channel) throws IOException {
+ String msg = new String(message.getBody(), "UTF-8");
+ System.out.println("msg = " + msg);
+ channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
+
+ // 重新发送消息到队尾
+ // 参数:Exchange、routingKey、额外的设置属性、消息字节数组
+ /*channel.basicPublish(message.getMessageProperties().getReceivedExchange(),
+ message.getMessageProperties().getReceivedRoutingKey(),
+ null,msg.getBytes());*/
+ }
+
+}
diff --git a/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/service/SendTalentsTemplate.java b/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/service/SendTalentsTemplate.java
new file mode 100644
index 000000000..4d015241b
--- /dev/null
+++ b/ruoyi-rabbitmq/src/main/java/com/ruoyi/mq/service/SendTalentsTemplate.java
@@ -0,0 +1,27 @@
+package com.ruoyi.mq.service;
+
+import com.ruoyi.mq.config.TalentsDelayRabbitConfig;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.core.MessageBuilder;
+import org.springframework.amqp.core.MessageDeliveryMode;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * 发送人才认定延时模板
+ */
+@Component
+public class SendTalentsTemplate {
+
+ @Autowired
+ private RabbitTemplate amqpTemplate;
+
+ public void sendDelayTalentsMsgStr(String msg){
+// 5*24=120小时=120*60分钟=7200分=7200*60秒=432000秒=432000*1000=432000000毫秒
+ Message build = MessageBuilder.withBody(msg.getBytes()).build();
+ build.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
+ build.getMessageProperties().setDelay(259200000);
+ amqpTemplate.convertAndSend(TalentsDelayRabbitConfig.TALENTS_PLUGIN_DELAY_EXCHANGE,TalentsDelayRabbitConfig.TALENTS_PLUGIN_DELAY_KEY,build);
+ }
+}
diff --git a/ruoyi-sms/src/main/java/com/ruoyi/sms/core/SmsTemplate.java b/ruoyi-sms/src/main/java/com/ruoyi/sms/core/SmsTemplate.java
new file mode 100644
index 000000000..e69de29bb
diff --git a/ruoyi-sms/src/main/java/com/ruoyi/sms/core/TelecomSendMsg.java b/ruoyi-sms/src/main/java/com/ruoyi/sms/core/TelecomSendMsg.java
new file mode 100644
index 000000000..1251e41d2
--- /dev/null
+++ b/ruoyi-sms/src/main/java/com/ruoyi/sms/core/TelecomSendMsg.java
@@ -0,0 +1,159 @@
+package com.ruoyi.sms.core;
+
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.http.HttpRequest;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.sms.entity.SmsResult;
+import org.springframework.stereotype.Service;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.HashMap;
+
+/**
+ * @author Administrator
+ */
+@Service
+public class TelecomSendMsg{
+ private final String url ="https://msg.cdht.org.cn:8082/apigbk/BatchSend2";
+ private final String CorpID ="jxxc";
+ private final String Pwd ="ULul@2023";
+
+ /**
+ * 发送短信验证码
+ * @param phones
+ * @param content
+ * @return
+ */
+ public SmsResult telecomSendCode(String phones, String content,String type) {
+ try {
+ HashMap paramMap = new HashMap<>();
+ paramMap.put("CorpID",CorpID);
+ paramMap.put("Pwd",Pwd);
+ paramMap.put("Mobile",phones);
+ String gbk = null;
+ if ("register".equals(type)){
+ gbk = URLEncoder.encode("尊敬的用户,您正在办理用户注册操作,我们不会向您索要此验证码,切勿告知他人。本次验证码有效性为:"+ Constants.CAPTCHA_EXPIRATION +"分钟,本次验证码为:"+content+"【成都高新人才安居资格认定】", "GBK");
+ }else if ("login".equals(type)){
+ gbk = URLEncoder.encode("尊敬的用户,您正在办理用户登录操作,我们不会向您索要此验证码,切勿告知他人。本次验证码有效性为:"+ Constants.CAPTCHA_EXPIRATION +"分钟,本次验证码为:"+content+"【成都高新人才安居资格认定】", "GBK");
+ }else if ("forgetPwd".equals(type)){
+ gbk = URLEncoder.encode("尊敬的用户,您正在办理用户忘记密码操作,我们不会向您索要此验证码,切勿告知他人。本次验证码有效性为:"+ Constants.CAPTCHA_EXPIRATION +"分钟,本次验证码为:"+content+"【成都高新人才安居资格认定】", "GBK");
+ }else if("updatePwd".equals(type)){
+ gbk = URLEncoder.encode("尊敬的用户,您正在办理用户修改密码,我们不会向您索要此验证码,切勿告知他人。本次验证码有效性为:"+ Constants.CAPTCHA_EXPIRATION +"分钟,本次验证码为:"+content+"【成都高新人才安居资格认定】", "GBK");
+ }else if ("updatePhone".equals(type)){
+
+ }
+ paramMap.put("Content",gbk);
+ String result = HttpRequest.get(url)
+ .form(paramMap)//表单内容
+ .timeout(20000)//超时,毫秒
+ .execute().body();
+ if (returnStatus(result)){
+ return SmsResult.builder()
+ .isSuccess(true)
+ .build();
+ }
+ throw new ServiceException("未知异常");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * 发送短信通知
+ * @param phones
+ * @param content
+ * @return
+ */
+ public SmsResult telecomSendNotice(String phones, String content) {
+ try {
+// String url ="https://msg.cdht.org.cn:8082/apigbk/BatchSend2";
+ HashMap paramMap = new HashMap<>();
+ paramMap.put("CorpID","jxxc");
+ paramMap.put("Pwd","ULul@2023");
+ paramMap.put("Mobile",phones);
+ String gbk = null;
+ gbk = URLEncoder.encode(content+"【成都高新人才安居资格认定】", "GBK");
+ paramMap.put("Content",gbk);
+ String result = HttpRequest.get(url)
+ .form(paramMap)//表单内容
+ .timeout(20000)//超时,毫秒
+ .execute().body();
+ if (returnStatus(result)){
+ return SmsResult.builder()
+ .isSuccess(true)
+ .build();
+ }
+ System.out.println("result2 = " + result);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ return null;
+ }
+
+
+ /**
+ * 状态返回值
+ * @param number
+ * @return
+ */
+ private boolean returnStatus(String number){
+ if (!StringUtils.isNumeric(number)) {
+ switch (number) {
+ case "-1":
+ throw new ServiceException("账户或密码错误,未获取到用户信息");
+ case "-2":
+ throw new ServiceException("其他错误(未知错误,网络波动,请稍后再试)");
+ case "-3":
+ throw new ServiceException("账户配置不正确");
+ case "-4":
+ throw new ServiceException("在禁止发送的时间段");
+ case "-5":
+ throw new ServiceException("余额不足,请充值");
+ case "-6":
+ throw new ServiceException("定时发送时间不是有效的时间格式");
+ case "-7":
+ throw new ServiceException("提交信息末尾未签名,请添加中文的企业签名【 】或内容乱码");
+ case "-8":
+ throw new ServiceException("发送号码数量超出系统限制");
+ case "-9":
+ throw new ServiceException("发送字数超出系统限制长度");
+ case "-10":
+ throw new ServiceException("产品不存在");
+ case "-11":
+ throw new ServiceException("内容不能再存在签名");
+ case "-12":
+ throw new ServiceException("传入参数不正确!");
+ case "-13":
+ throw new ServiceException("手机号校验不正确");
+ case "-14":
+ throw new ServiceException("内容中存在黑字典关键字");
+ case "-15":
+ throw new ServiceException("定时时间格式错误");
+ case "-16":
+ throw new ServiceException("扩展号格式不正确");
+ case "-17":
+ throw new ServiceException("子号池全被占用,请等待释放后再操作");
+ case "-18":
+ throw new ServiceException("该扩展号被投票问卷占用,请使用其他的扩展");
+ case "-19":
+ throw new ServiceException("SendSms计费类型选择不正确");
+ case "-100":
+ throw new ServiceException("发送失败");
+ case "-101":
+ throw new ServiceException("调用频率过快");
+ case "-103":
+ throw new ServiceException("IP未导白");
+ case "-111":
+ throw new ServiceException("个性短信入口错误");
+ case "-200":
+ throw new ServiceException("网络连接失败");
+ case "-401":
+ throw new ServiceException("账号没有调用接口权限,请联系客服专员");
+ }
+ }
+ return true;
+ }
+}
diff --git a/ruoyi-sms/src/main/java/com/ruoyi/sms/entity/SmsResult.java b/ruoyi-sms/src/main/java/com/ruoyi/sms/entity/SmsResult.java
new file mode 100644
index 000000000..89c39b403
--- /dev/null
+++ b/ruoyi-sms/src/main/java/com/ruoyi/sms/entity/SmsResult.java
@@ -0,0 +1,31 @@
+package com.ruoyi.sms.entity;
+
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * 上传返回体
+ *
+ * @author Lion Li
+ */
+@Data
+@Builder
+public class SmsResult {
+
+ /**
+ * 是否成功
+ */
+ private boolean isSuccess;
+
+ /**
+ * 响应消息
+ */
+ private String message;
+
+ /**
+ * 实际响应体
+ *