diff --git a/eladmin-common/src/main/java/me/zhengjie/annotation/AnonymousAccess.java b/eladmin-common/src/main/java/me/zhengjie/annotation/AnonymousAccess.java index d5021aa9..b2c168fe 100644 --- a/eladmin-common/src/main/java/me/zhengjie/annotation/AnonymousAccess.java +++ b/eladmin-common/src/main/java/me/zhengjie/annotation/AnonymousAccess.java @@ -15,16 +15,15 @@ */ package me.zhengjie.annotation; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import java.lang.annotation.*; /** * @author jacky * 用于标记匿名访问方法 */ -@Target(ElementType.METHOD) +@Inherited +@Documented +@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface AnonymousAccess { diff --git a/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousDeleteMapping.java b/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousDeleteMapping.java new file mode 100644 index 00000000..6a81c2e9 --- /dev/null +++ b/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousDeleteMapping.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import me.zhengjie.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code DELETE} requests onto specific handler + * methods. + * 支持匿名访问 DeleteMapping + * + * @author liaojinlong + * @see AnonymousGetMapping + * @see AnonymousPostMapping + * @see AnonymousPutMapping + * @see AnonymousPatchMapping + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.DELETE) +public @interface AnonymousDeleteMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousGetMapping.java b/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousGetMapping.java new file mode 100644 index 00000000..c260a71b --- /dev/null +++ b/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousGetMapping.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import me.zhengjie.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code GET} requests onto specific handler + * methods. + *

+ * 支持匿名访问 GetMapping + * + * @author liaojinlong + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.GET) +public @interface AnonymousGetMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + * + * @since 4.3.5 + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPatchMapping.java b/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPatchMapping.java new file mode 100644 index 00000000..66866178 --- /dev/null +++ b/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPatchMapping.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import me.zhengjie.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code PATCH} requests onto specific handler + * methods. + * * 支持匿名访问 PatchMapping + * + * @author liaojinlong + * @see AnonymousGetMapping + * @see AnonymousPostMapping + * @see AnonymousPutMapping + * @see AnonymousDeleteMapping + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.PATCH) +public @interface AnonymousPatchMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPostMapping.java b/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPostMapping.java new file mode 100644 index 00000000..8f1cdcdd --- /dev/null +++ b/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPostMapping.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import me.zhengjie.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code POST} requests onto specific handler + * methods. + * 支持匿名访问 PostMapping + * + * @author liaojinlong + * @see AnonymousGetMapping + * @see AnonymousPostMapping + * @see AnonymousPutMapping + * @see AnonymousDeleteMapping + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.POST) +public @interface AnonymousPostMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPutMapping.java b/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPutMapping.java new file mode 100644 index 00000000..7c417dac --- /dev/null +++ b/eladmin-common/src/main/java/me/zhengjie/annotation/rest/AnonymousPutMapping.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import me.zhengjie.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code PUT} requests onto specific handler + * methods. + * * 支持匿名访问 PutMapping + * + * @author liaojinlong + * @see AnonymousGetMapping + * @see AnonymousPostMapping + * @see AnonymousPutMapping + * @see AnonymousDeleteMapping + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.PUT) +public @interface AnonymousPutMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/eladmin-common/src/main/java/me/zhengjie/utils/CallBack.java b/eladmin-common/src/main/java/me/zhengjie/utils/CallBack.java new file mode 100644 index 00000000..92ceb085 --- /dev/null +++ b/eladmin-common/src/main/java/me/zhengjie/utils/CallBack.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zhengjie.utils; + +import java.io.IOException; + +/** + * @author: liaojinlong + * @date: 2020/6/9 17:02 + * @since: 1.0 + * @see {@link SpringContextHolder} + * 针对某些初始化方法,在SpringContextHolder 初始化前时,
+ * 可提交一个 提交回调任务。
+ * 在SpringContextHolder 初始化后,进行回调使用 + */ + +public interface CallBack { + /** + * 回调执行方法 + */ + void executor(); + + /** + * 本回调任务名称 + * + * @return + */ + default String getCallBackName() { + return Thread.currentThread().getId() + ":" + this.getClass().getName(); + } +} + diff --git a/eladmin-common/src/main/java/me/zhengjie/utils/ElAdminConstant.java b/eladmin-common/src/main/java/me/zhengjie/utils/ElAdminConstant.java index b62f86f9..127ec43a 100644 --- a/eladmin-common/src/main/java/me/zhengjie/utils/ElAdminConstant.java +++ b/eladmin-common/src/main/java/me/zhengjie/utils/ElAdminConstant.java @@ -17,11 +17,16 @@ package me.zhengjie.utils; /** * 常用静态常量 + * * @author Zheng Jie * @date 2018-12-26 */ public class ElAdminConstant { + /** + * 用于IP定位转换 + */ + public static final String REGION = "内网IP|内网IP"; /** * win 系统 */ @@ -35,7 +40,7 @@ public class ElAdminConstant { /** * 常用接口 */ - public static class Url{ + public static class Url { // 免费图床 public static final String SM_MS_URL = "https://sm.ms/api"; // IP归属地查询 diff --git a/eladmin-common/src/main/java/me/zhengjie/utils/FileUtil.java b/eladmin-common/src/main/java/me/zhengjie/utils/FileUtil.java index 8a6baf2e..b1a64af8 100644 --- a/eladmin-common/src/main/java/me/zhengjie/utils/FileUtil.java +++ b/eladmin-common/src/main/java/me/zhengjie/utils/FileUtil.java @@ -22,6 +22,7 @@ import cn.hutool.poi.excel.ExcelUtil; import me.zhengjie.exception.BadRequestException; import org.apache.poi.util.IOUtils; import org.springframework.web.multipart.MultipartFile; + import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -35,6 +36,7 @@ import java.util.Map; /** * File工具类,扩展 hutool 工具包 + * * @author Zheng Jie * @date 2018-12-27 */ @@ -61,11 +63,11 @@ public class FileUtil extends cn.hutool.core.io.FileUtil { /** * MultipartFile转File */ - public static File toFile(MultipartFile multipartFile){ + public static File toFile(MultipartFile multipartFile) { // 获取文件名 String fileName = multipartFile.getOriginalFilename(); // 获取文件后缀 - String prefix="."+getExtensionName(fileName); + String prefix = "." + getExtensionName(fileName); File file = null; try { // 用uuid作为文件名,防止生成的临时文件重复 @@ -84,7 +86,7 @@ public class FileUtil extends cn.hutool.core.io.FileUtil { public static String getExtensionName(String filename) { if ((filename != null) && (filename.length() > 0)) { int dot = filename.lastIndexOf('.'); - if ((dot >-1) && (dot < (filename.length() - 1))) { + if ((dot > -1) && (dot < (filename.length() - 1))) { return filename.substring(dot + 1); } } @@ -97,7 +99,7 @@ public class FileUtil extends cn.hutool.core.io.FileUtil { public static String getFileNameNoEx(String filename) { if ((filename != null) && (filename.length() > 0)) { int dot = filename.lastIndexOf('.'); - if ((dot >-1) && (dot < (filename.length()))) { + if ((dot > -1) && (dot < (filename.length()))) { return filename.substring(0, dot); } } @@ -107,7 +109,7 @@ public class FileUtil extends cn.hutool.core.io.FileUtil { /** * 文件大小转换 */ - public static String getSize(long size){ + public static String getSize(long size) { String resultSize; if (size / GB >= 1) { //如果当前Byte的值大于等于1GB @@ -124,6 +126,26 @@ public class FileUtil extends cn.hutool.core.io.FileUtil { return resultSize; } + /** + * inputStream 转 File + */ + static File inputStreamToFile(InputStream ins, String name) throws Exception { + File file = new File(System.getProperty("java.io.tmpdir") + File.separator + name); + if (file.exists()) { + return file; + } + OutputStream os = new FileOutputStream(file); + int bytesRead; + int len = 8192; + byte[] buffer = new byte[len]; + while ((bytesRead = ins.read(buffer, 0, len)) != -1) { + os.write(buffer, 0, bytesRead); + } + os.close(); + ins.close(); + return file; + } + /** * 将文件名解析成文件的上传路径 */ @@ -157,16 +179,16 @@ public class FileUtil extends cn.hutool.core.io.FileUtil { * 导出excel */ public static void downloadExcel(List> list, HttpServletResponse response) throws IOException { - String tempPath =System.getProperty("java.io.tmpdir") + IdUtil.fastSimpleUUID() + ".xlsx"; + String tempPath = System.getProperty("java.io.tmpdir") + IdUtil.fastSimpleUUID() + ".xlsx"; File file = new File(tempPath); - BigExcelWriter writer= ExcelUtil.getBigWriter(file); + BigExcelWriter writer = ExcelUtil.getBigWriter(file); // 一次性写出内容,使用默认样式,强制输出标题 writer.write(list, true); //response为HttpServletResponse对象 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码 - response.setHeader("Content-Disposition","attachment;filename=file.xlsx"); - ServletOutputStream out=response.getOutputStream(); + response.setHeader("Content-Disposition", "attachment;filename=file.xlsx"); + ServletOutputStream out = response.getOutputStream(); // 终止后删除临时文件 file.deleteOnExit(); writer.flush(out, true); @@ -179,13 +201,13 @@ public class FileUtil extends cn.hutool.core.io.FileUtil { String music = "mp3 wav wma mpa ram ra aac aif m4a"; String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg"; String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg"; - if(image.contains(type)){ + if (image.contains(type)) { return "图片"; - } else if(documents.contains(type)){ + } else if (documents.contains(type)) { return "文档"; - } else if(music.contains(type)){ + } else if (music.contains(type)) { return "音乐"; - } else if(video.contains(type)){ + } else if (video.contains(type)) { return "视频"; } else { return "其他"; @@ -195,7 +217,7 @@ public class FileUtil extends cn.hutool.core.io.FileUtil { public static void checkSize(long maxSize, long size) { // 1M int len = 1024 * 1024; - if(size > (maxSize * len)){ + if (size > (maxSize * len)) { throw new BadRequestException("文件超出规定大小"); } } @@ -257,18 +279,19 @@ public class FileUtil extends cn.hutool.core.io.FileUtil { /** * 下载文件 - * @param request / + * + * @param request / * @param response / - * @param file / + * @param file / */ - public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit){ + public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit) { response.setCharacterEncoding(request.getCharacterEncoding()); response.setContentType("application/octet-stream"); FileInputStream fis = null; try { fis = new FileInputStream(file); - response.setHeader("Content-Disposition", "attachment; filename="+file.getName()); - IOUtils.copy(fis,response.getOutputStream()); + response.setHeader("Content-Disposition", "attachment; filename=" + file.getName()); + IOUtils.copy(fis, response.getOutputStream()); response.flushBuffer(); } catch (Exception e) { e.printStackTrace(); @@ -276,7 +299,7 @@ public class FileUtil extends cn.hutool.core.io.FileUtil { if (fis != null) { try { fis.close(); - if(deleteOnExit){ + if (deleteOnExit) { file.deleteOnExit(); } } catch (IOException e) { diff --git a/eladmin-common/src/main/java/me/zhengjie/utils/SpringContextHolder.java b/eladmin-common/src/main/java/me/zhengjie/utils/SpringContextHolder.java index 8da0dab7..8a7f6433 100644 --- a/eladmin-common/src/main/java/me/zhengjie/utils/SpringContextHolder.java +++ b/eladmin-common/src/main/java/me/zhengjie/utils/SpringContextHolder.java @@ -20,6 +20,10 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.DisposableBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.core.env.Environment; + +import java.util.ArrayList; +import java.util.List; /** * @author Jie @@ -29,6 +33,23 @@ import org.springframework.context.ApplicationContextAware; public class SpringContextHolder implements ApplicationContextAware, DisposableBean { private static ApplicationContext applicationContext = null; + private static List callBacks = new ArrayList<>(); + private static boolean addCallback = true; + + /** + * 针对 某些初始化方法,在SpringContextHolder 未初始化时 提交回调方法。 + * 在SpringContextHolder 初始化后,进行回调使用 + * + * @param callBack 回调函数 + */ + public synchronized static void addCallBacks(CallBack callBack) { + if (addCallback) { + SpringContextHolder.callBacks.add(callBack); + } else { + log.warn("CallBack:{} 已无法添加!立即执行", callBack.getCallBackName()); + callBack.executor(); + } + } /** * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. @@ -47,6 +68,44 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB return applicationContext.getBean(requiredType); } + /** + * 获取SpringBoot 配置信息 + * + * @param property 属性key + * @param defaultValue 默认值 + * @param requiredType 返回类型 + * @return + */ + public static T getProperties(String property, T defaultValue, Class requiredType) { + T result = defaultValue; + try { + result = getBean(Environment.class).getProperty(property, requiredType); + } catch (Exception e) { + } + return result; + } + + /** + * 获取SpringBoot 配置信息 + * + * @param property 属性key + * @return + */ + public static String getProperties(String property) { + return getProperties(property, null, String.class); + } + + /** + * 获取SpringBoot 配置信息 + * + * @param property 属性key + * @param requiredType 返回类型 + * @return + */ + public static T getProperties(String property, Class requiredType) { + return getProperties(property, null, requiredType); + } + /** * 检查ApplicationContext不为空. */ @@ -67,7 +126,7 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB } @Override - public void destroy(){ + public void destroy() { SpringContextHolder.clearHolder(); } @@ -77,5 +136,12 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext); } SpringContextHolder.applicationContext = applicationContext; + if (addCallback) { + for (CallBack callBack : SpringContextHolder.callBacks) { + callBack.executor(); + } + callBacks.clear(); + } + SpringContextHolder.addCallback = false; } } diff --git a/eladmin-common/src/main/java/me/zhengjie/utils/StringUtils.java b/eladmin-common/src/main/java/me/zhengjie/utils/StringUtils.java index 33bfc51c..8daab9f5 100644 --- a/eladmin-common/src/main/java/me/zhengjie/utils/StringUtils.java +++ b/eladmin-common/src/main/java/me/zhengjie/utils/StringUtils.java @@ -20,7 +20,18 @@ import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import eu.bitwalker.useragentutils.Browser; import eu.bitwalker.useragentutils.UserAgent; +import org.lionsoul.ip2region.DataBlock; +import org.lionsoul.ip2region.DbConfig; +import org.lionsoul.ip2region.DbMakerConfigException; +import org.lionsoul.ip2region.DbSearcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; + import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.io.FileNotFoundException; + import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Calendar; @@ -31,6 +42,34 @@ import java.util.Date; * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类 */ public class StringUtils extends org.apache.commons.lang3.StringUtils { + private static final Logger log = LoggerFactory.getLogger(StringUtils.class); + private static boolean ipLocal = false; + private static DbSearcher searcher = null; + + static { + SpringContextHolder.addCallBacks(() -> { + StringUtils.ipLocal = SpringContextHolder.getProperties("ip.local-parsing", false, Boolean.class); + if (ipLocal) { + /** + * 此文件为独享 ,不必关闭 + */ + String path = "ip2region/ip2region.db"; + String name = "ip2region.db"; + DbConfig config = null; + try { + config = new DbConfig(); + File file = FileUtil.inputStreamToFile(new ClassPathResource(path).getInputStream(), name); + searcher = new DbSearcher(config, file.getPath()); + } catch (DbMakerConfigException | FileNotFoundException e) { + log.error(e.getMessage(), e); + } catch (NoSuchMethodException e) { + log.error(e.getMessage(), e); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + }); + } private static final char SEPARATOR = '_'; @@ -140,12 +179,12 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { if (ip.contains(comma)) { ip = ip.split(",")[0]; } - if (localhost.equals(ip)) { + if (localhost.equals(ip)) { // 获取本机真正的ip地址 try { ip = InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { - e.printStackTrace(); + log.error(e.getMessage(), e); } } return ip; @@ -155,12 +194,42 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { * 根据ip获取详细地址 */ public static String getCityInfo(String ip) { - String api = String.format(ElAdminConstant.Url.IP_URL,ip); + if (ipLocal) { + return getLocalCityInfo(ip); + } else { + return getHttpCityInfo(ip); + } + } + + /** + * 根据ip获取详细地址 + */ + public static String getHttpCityInfo(String ip) { + String api = String.format(ElAdminConstant.Url.IP_URL, ip); JSONObject object = JSONUtil.parseObj(HttpUtil.get(api)); return object.get("addr", String.class); } - public static String getBrowser(HttpServletRequest request){ + /** + * 根据ip获取详细地址 + */ + public static String getLocalCityInfo(String ip) { + try { + DataBlock dataBlock; + dataBlock = searcher.binarySearch(ip); + String address = dataBlock.getRegion().replace("0|", ""); + char symbol = '|'; + if (address.charAt(address.length() - 1) == symbol) { + address = address.substring(0, address.length() - 1); + } + return address.equals(ElAdminConstant.REGION) ? "内网IP" : address; + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return ""; + } + + public static String getBrowser(HttpServletRequest request) { UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent")); Browser browser = userAgent.getBrowser(); return browser.getName(); @@ -169,13 +238,13 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { /** * 获得当天是周几 */ - public static String getWeekDay(){ + public static String getWeekDay() { String[] weekDays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; Calendar cal = Calendar.getInstance(); cal.setTime(new Date()); int w = cal.get(Calendar.DAY_OF_WEEK) - 1; - if (w < 0){ + if (w < 0) { w = 0; } return weekDays[w]; @@ -183,9 +252,10 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { /** * 获取当前机器的IP + * * @return / */ - public static String getLocalIp(){ + public static String getLocalIp() { InetAddress addr; try { addr = InetAddress.getLocalHost(); diff --git a/eladmin-system/src/main/java/me/zhengjie/AppRun.java b/eladmin-system/src/main/java/me/zhengjie/AppRun.java index d0540c4f..ed244064 100644 --- a/eladmin-system/src/main/java/me/zhengjie/AppRun.java +++ b/eladmin-system/src/main/java/me/zhengjie/AppRun.java @@ -16,7 +16,7 @@ package me.zhengjie; import io.swagger.annotations.Api; -import me.zhengjie.annotation.AnonymousAccess; +import me.zhengjie.annotation.rest.AnonymousGetMapping; import me.zhengjie.utils.SpringContextHolder; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -26,11 +26,11 @@ import org.springframework.context.annotation.Bean; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.transaction.annotation.EnableTransactionManagement; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * 开启审计功能 -> @EnableJpaAuditing + * * @author Zheng Jie * @date 2018/11/15 9:20:19 */ @@ -60,10 +60,10 @@ public class AppRun { /** * 访问首页提示 + * * @return / */ - @GetMapping("/") - @AnonymousAccess + @AnonymousGetMapping("/") public String index() { return "Backend service started successfully"; } diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/rest/AuthorizationController.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/rest/AuthorizationController.java index e57f0927..8f4c39cd 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/rest/AuthorizationController.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/rest/AuthorizationController.java @@ -21,8 +21,10 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import me.zhengjie.annotation.AnonymousAccess; import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.rest.AnonymousDeleteMapping; +import me.zhengjie.annotation.rest.AnonymousGetMapping; +import me.zhengjie.annotation.rest.AnonymousPostMapping; import me.zhengjie.config.RsaProperties; import me.zhengjie.exception.BadRequestException; import me.zhengjie.modules.security.config.SecurityProperties; @@ -43,6 +45,7 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; + import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; @@ -72,8 +75,7 @@ public class AuthorizationController { @Log("用户登录") @ApiOperation("登录授权") - @AnonymousAccess - @PostMapping(value = "/login") + @AnonymousPostMapping(value = "/login") public ResponseEntity login(@Validated @RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception { // 密码解密 String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, authUser.getPassword()); @@ -98,27 +100,26 @@ public class AuthorizationController { // 保存在线信息 onlineUserService.save(jwtUserDto, token, request); // 返回 token 与 用户信息 - Map authInfo = new HashMap(2){{ + Map authInfo = new HashMap(2) {{ put("token", properties.getTokenStartWith() + token); put("user", jwtUserDto); }}; - if(singleLogin){ + if (singleLogin) { //踢掉之前已经登录的token - onlineUserService.checkLoginOnUser(authUser.getUsername(),token); + onlineUserService.checkLoginOnUser(authUser.getUsername(), token); } return ResponseEntity.ok(authInfo); } @ApiOperation("获取用户信息") @GetMapping(value = "/info") - public ResponseEntity getUserInfo(){ + public ResponseEntity getUserInfo() { return ResponseEntity.ok(SecurityUtils.getCurrentUser()); } - @AnonymousAccess @ApiOperation("获取验证码") - @GetMapping(value = "/code") - public ResponseEntity getCode(){ + @AnonymousGetMapping(value = "/code") + public ResponseEntity getCode() { // 算术类型 https://gitee.com/whvse/EasyCaptcha ArithmeticCaptcha captcha = new ArithmeticCaptcha(111, 36); // 几位数运算,默认是两位 @@ -129,7 +130,7 @@ public class AuthorizationController { // 保存 redisUtils.set(uuid, result, expiration, TimeUnit.MINUTES); // 验证码信息 - Map imgResult = new HashMap(2){{ + Map imgResult = new HashMap(2) {{ put("img", captcha.toBase64()); put("uuid", uuid); }}; @@ -137,9 +138,8 @@ public class AuthorizationController { } @ApiOperation("退出登录") - @AnonymousAccess - @DeleteMapping(value = "/logout") - public ResponseEntity logout(HttpServletRequest request){ + @AnonymousDeleteMapping(value = "/logout") + public ResponseEntity logout(HttpServletRequest request) { onlineUserService.logout(tokenProvider.getToken(request)); return new ResponseEntity<>(HttpStatus.OK); } diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/system/rest/LimitController.java b/eladmin-system/src/main/java/me/zhengjie/modules/system/rest/LimitController.java index 43557d8e..329c5ac6 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/system/rest/LimitController.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/system/rest/LimitController.java @@ -17,11 +17,11 @@ package me.zhengjie.modules.system.rest; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; -import me.zhengjie.annotation.AnonymousAccess; import me.zhengjie.annotation.Limit; -import org.springframework.web.bind.annotation.GetMapping; +import me.zhengjie.annotation.rest.AnonymousGetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; + import java.util.concurrent.atomic.AtomicInteger; /** @@ -38,8 +38,7 @@ public class LimitController { /** * 测试限流注解,下面配置说明该接口 60秒内最多只能访问 10次,保存到redis的键名为 limit_test, */ - @GetMapping - @AnonymousAccess + @AnonymousGetMapping @ApiOperation("测试") @Limit(key = "test", period = 60, count = 10, name = "testLimit", prefix = "limit") public int test() { diff --git a/eladmin-system/src/main/resources/config/application-dev.yml b/eladmin-system/src/main/resources/config/application-dev.yml index 4e97dc84..d7723b5b 100644 --- a/eladmin-system/src/main/resources/config/application-dev.yml +++ b/eladmin-system/src/main/resources/config/application-dev.yml @@ -73,6 +73,11 @@ generator: #是否开启 swagger-ui swagger: enabled: true +# IP 本地解析 + +ip: + local-parsing: true + # 文件存储路径 file: @@ -87,4 +92,4 @@ file: avatar: C:\eladmin\avatar\ # 文件大小 /M maxSize: 100 - avatarMaxSize: 5 \ No newline at end of file + avatarMaxSize: 5 diff --git a/eladmin-system/src/main/resources/ip2region/ip2region.db b/eladmin-system/src/main/resources/ip2region/ip2region.db new file mode 100644 index 00000000..43e1daf5 Binary files /dev/null and b/eladmin-system/src/main/resources/ip2region/ip2region.db differ diff --git a/eladmin-tools/src/main/java/me/zhengjie/rest/AliPayController.java b/eladmin-tools/src/main/java/me/zhengjie/rest/AliPayController.java index a1bad94e..128bb404 100644 --- a/eladmin-tools/src/main/java/me/zhengjie/rest/AliPayController.java +++ b/eladmin-tools/src/main/java/me/zhengjie/rest/AliPayController.java @@ -21,6 +21,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import me.zhengjie.annotation.AnonymousAccess; import me.zhengjie.annotation.Log; +import me.zhengjie.annotation.rest.AnonymousGetMapping; import me.zhengjie.domain.vo.TradeVo; import me.zhengjie.domain.AlipayConfig; import me.zhengjie.utils.AliPayStatusEnum; @@ -31,6 +32,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.nio.charset.StandardCharsets; @@ -51,14 +53,14 @@ public class AliPayController { private final AliPayService alipayService; @GetMapping - public ResponseEntity queryConfig(){ - return new ResponseEntity<>(alipayService.find(),HttpStatus.OK); + public ResponseEntity queryConfig() { + return new ResponseEntity<>(alipayService.find(), HttpStatus.OK); } @Log("配置支付宝") @ApiOperation("配置支付宝") @PutMapping - public ResponseEntity updateConfig(@Validated @RequestBody AlipayConfig alipayConfig){ + public ResponseEntity updateConfig(@Validated @RequestBody AlipayConfig alipayConfig) { alipayService.config(alipayConfig); return new ResponseEntity<>(HttpStatus.OK); } @@ -66,41 +68,40 @@ public class AliPayController { @Log("支付宝PC网页支付") @ApiOperation("PC网页支付") @PostMapping(value = "/toPayAsPC") - public ResponseEntity toPayAsPc(@Validated@RequestBody TradeVo trade) throws Exception{ + public ResponseEntity toPayAsPc(@Validated @RequestBody TradeVo trade) throws Exception { AlipayConfig aliPay = alipayService.find(); trade.setOutTradeNo(alipayUtils.getOrderCode()); - String payUrl = alipayService.toPayAsPc(aliPay,trade); + String payUrl = alipayService.toPayAsPc(aliPay, trade); return ResponseEntity.ok(payUrl); } @Log("支付宝手机网页支付") @ApiOperation("手机网页支付") @PostMapping(value = "/toPayAsWeb") - public ResponseEntity toPayAsWeb(@Validated @RequestBody TradeVo trade) throws Exception{ + public ResponseEntity toPayAsWeb(@Validated @RequestBody TradeVo trade) throws Exception { AlipayConfig alipay = alipayService.find(); trade.setOutTradeNo(alipayUtils.getOrderCode()); - String payUrl = alipayService.toPayAsWeb(alipay,trade); + String payUrl = alipayService.toPayAsWeb(alipay, trade); return ResponseEntity.ok(payUrl); } @ApiIgnore - @GetMapping("/return") - @AnonymousAccess + @AnonymousGetMapping("/return") @ApiOperation("支付之后跳转的链接") - public ResponseEntity returnPage(HttpServletRequest request, HttpServletResponse response){ + public ResponseEntity returnPage(HttpServletRequest request, HttpServletResponse response) { AlipayConfig alipay = alipayService.find(); response.setContentType("text/html;charset=" + alipay.getCharset()); //内容验签,防止黑客篡改参数 - if(alipayUtils.rsaCheck(request,alipay)){ + if (alipayUtils.rsaCheck(request, alipay)) { //商户订单号 String outTradeNo = new String(request.getParameter("out_trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); //支付宝交易号 String tradeNo = new String(request.getParameter("trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); - System.out.println("商户订单号"+outTradeNo+" "+"第三方交易号"+tradeNo); + System.out.println("商户订单号" + outTradeNo + " " + "第三方交易号" + tradeNo); // 根据业务需要返回数据,这里统一返回OK - return new ResponseEntity<>("payment successful",HttpStatus.OK); - }else{ + return new ResponseEntity<>("payment successful", HttpStatus.OK); + } else { // 根据业务需要返回数据 return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } @@ -109,13 +110,12 @@ public class AliPayController { @ApiIgnore @RequestMapping("/notify") @AnonymousAccess - @SuppressWarnings("all") @ApiOperation("支付异步通知(要公网访问),接收异步通知,检查通知内容app_id、out_trade_no、total_amount是否与请求中的一致,根据trade_status进行后续业务处理") - public ResponseEntity notify(HttpServletRequest request){ + public ResponseEntity notify(HttpServletRequest request) { AlipayConfig alipay = alipayService.find(); Map parameterMap = request.getParameterMap(); //内容验签,防止黑客篡改参数 - if (alipayUtils.rsaCheck(request,alipay)) { + if (alipayUtils.rsaCheck(request, alipay)) { //交易状态 String tradeStatus = new String(request.getParameter("trade_status").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); // 商户订单号 @@ -125,8 +125,8 @@ public class AliPayController { //付款金额 String totalAmount = new String(request.getParameter("total_amount").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); //验证 - if(tradeStatus.equals(AliPayStatusEnum.SUCCESS.getValue())||tradeStatus.equals(AliPayStatusEnum.FINISHED.getValue())){ - // 验证通过后应该根据业务需要处理订单 + if (tradeStatus.equals(AliPayStatusEnum.SUCCESS.getValue()) || tradeStatus.equals(AliPayStatusEnum.FINISHED.getValue())) { + // 验证通过后应该根据业务需要处理订单 } return new ResponseEntity<>(HttpStatus.OK); } diff --git a/pom.xml b/pom.xml index 2d0b001a..37b171f6 100644 --- a/pom.xml +++ b/pom.xml @@ -139,7 +139,11 @@ druid-spring-boot-starter ${druid.version} - + + org.lionsoul + ip2region + 1.7.2 + org.projectlombok