当前位置: 首页 > news >正文

苏州建设网站多少钱制作网站的列子

苏州建设网站多少钱,制作网站的列子,seo排名软件哪个好,app制作图片前言 你知道自定义注解的魅力所在吗#xff1f; 你知道自定义注解该怎么使用吗#xff1f; 本文一开始的这两个问题#xff0c;需要您仔细思考下#xff0c;然后结合这两个问题来阅读下面的内容#xff1b; 本文主线#xff1a; 注解是什么#xff1b;实现一个自定义注…前言 你知道自定义注解的魅力所在吗 你知道自定义注解该怎么使用吗 本文一开始的这两个问题需要您仔细思考下然后结合这两个问题来阅读下面的内容 本文主线 注解是什么实现一个自定义注解自定义注解的实战应用场景 注意本文在介绍自定义注解实战应用场景时需要结合拦截器、AOP进行使用所以本文也会简单聊下AOP相关知识点如果对于AOP的相关内容不太清楚的可以参考此 细说Spring——AOP详解 文章进行了解。 注解 注解是什么 ①、引用自维基百科的内容 Java注解又称Java标注是JDK5.0版本开始支持加入源代码的特殊语法 元数据 。 Java语言中的类、方法、变量、参数和包等都可以被标注。和Javadoc不同Java标注可以通过反射获取标注内容。在编译器生成类文件时标注可以被嵌入到字节码中。Java虚拟机可以保留标注内容在运行时可以获取到标注内容。 当然它也支持自定义Java标注。 ②、引用自网络的内容 Java 注解是在 JDK5 时引入的新特性注解也被称为 元数据 为我们在代码中添加信息提供了一种形式化的方法使我们可以在稍后某个时刻非常方便地使用这些数据。 元注解是什么 元注解 的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation元注解类型它们被用来提供对其它 annotation类型作说明。 标准的元注解 TargetRetentionDocumentedInherited 在详细说这四个元数据的含义之前先来看一个在工作中会经常使用到的 Autowired 注解进入这个注解里面瞧瞧 此注解中使用到了Target、Retention、Documented 这三个元注解 。 Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) Retention(RetentionPolicy.RUNTIME) Documented public interface Autowired {boolean required() default true; }Target元注解 Target注解是专门用来限定某个自定义注解能够被应用在哪些Java元素上面的标明作用范围取值在 java.lang.annotation.ElementType 进行定义的。 public enum ElementType {/** 类接口包括注解类型或枚举的声明 */TYPE,/** 属性的声明 */FIELD,/** 方法的声明 */METHOD,/** 方法形式参数声明 */PARAMETER,/** 构造方法的声明 */CONSTRUCTOR,/** 局部变量声明 */LOCAL_VARIABLE,/** 注解类型声明 */ANNOTATION_TYPE,/** 包的声明 */PACKAGE }根据此处可以知道 Autowired 注解的作用范围 // 可以作用在 构造方法、方法、方法形参、属性、注解类型 上 Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})Retention元注解 Retention注解翻译为持久力、保持力。即用来修饰自定义注解的生命周期。 注解的生命周期有三个阶段 Java源文件阶段编译到class文件阶段运行期阶段 同样使用了RetentionPolicy 枚举类型对这三个阶段进行了定义 public enum RetentionPolicy {/*** Annotations are to be discarded by the compiler.* 注解将被编译器忽略掉*/SOURCE,/*** Annotations are to be recorded in the class file by the compiler* but need not be retained by the VM at run time. This is the default* behavior.* 注解将被编译器记录在class文件中但在运行时不会被虚拟机保留这是一个默认的行为*/CLASS,/*** Annotations are to be recorded in the class file by the compiler and* retained by the VM at run time, so they may be read reflectively.* 注解将被编译器记录在class文件中而且在运行时会被虚拟机保留因此它们能通过反射被读取到* see java.lang.reflect.AnnotatedElement*/RUNTIME }再详细描述下这三个阶段 ①、如果被定义为 RetentionPolicy.SOURCE则它将被限定在Java源文件中那么这个注解即不会参与编译也不会在运行期起任何作用这个注解就和一个注释是一样的效果只能被阅读Java文件的人看到 ②、如果被定义为 RetentionPolicy.CLASS则它将被编译到Class文件中那么编译器可以在编译时根据注解做一些处理动作但是运行时JVMJava虚拟机会忽略它并且在运行期也不能读取到 ③、如果被定义为 RetentionPolicy.RUNTIME那么这个注解可以在运行期的加载阶段被加载到Class对象中。那么在程序运行阶段可以通过反射得到这个注解并通过判断是否有这个注解或这个注解中属性的值从而执行不同的程序代码段。 注意实际开发中的自定义注解几乎都是使用的 RetentionPolicy.RUNTIME 。 Documented元注解 Documented注解是被用来指定自定义注解是否能随着被定义的java文件生成到JavaDoc文档当中。 Inherited元注解 Inherited注解是指定某个自定义注解如果写在了父类的声明部分那么子类的声明部分也能自动拥有该注解。 Inherited注解只对那些Target被定义为 ElementType.TYPE 的自定义注解起作用。 自定义注解实现 在了解了上面的内容后我们来尝试实现一个自定义注解 根据上面自定义注解中使用到的元注解得知 ①、此注解的作用范围可以使用在类接口、枚举、方法上 ②、此注解的生命周期被编译器保存在class文件中而且在运行时会被JVM保留可以通过反射读取 自定义注解的简单使用 上面已经创建了一个自定义的注解那该怎么使用呢下面首先描述下它简单的用法后面将会使用其结合拦截器和AOP切面编程进行实战应用 应用场景实现 在了解了上面注解的知识后我们乘胜追击看看它的实际应用场景是肿么样的以此加深下我们的理解 实现的 Demo 项目是以 SpringBoot 实现的项目工程结构图如下 场景一自定义注解 拦截器 实现接口响应的包装 使用自定义注解 结合 拦截器 优雅的实现对API接口响应的包装。 在介绍自定义实现的方式之前先简单介绍下普遍的实现方式通过两者的对比才能更加明显的发现谁最优雅。 普通的接口响应包装方式 现在项目绝大部分都采用的前后端分离方式所以需要前端和后端通过接口进行交互目前在接口交互中使用最多的数据格式是 json然后后端返回给前端的最为常见的响应格式如下 {#返回状态码code:integer, #返回信息描述message:string,#返回数据值data:object }项目中经常使用枚举类定义状态码和消息代码如下 /*** Description: 使用枚举类封装好的响应状态码及对应的响应消息*/ public enum ResponseCode {SUCCESS(1200, 请求成功),ERROR(1400, 请求失败);private Integer code;private String message;private ResponseCode(Integer code, String message) {this.code code;this.message message;}public Integer code() {return this.code;}public String message() {return this.message;}}同时项目中也会设计一个返回响应包装类代码如下 import com.alibaba.fastjson.JSONObject; import java.io.Serializable;/*** Description: 封装的统一的响应返回类*/ SuppressWarnings(serial) public class ResponseT implements Serializable {/*** 响应数据*/private T date;/*** 响应状态码*/private Integer code;/*** 响应描述信息*/private String message;public Response(T date, Integer code, String message) {super();this.date date;this.code code;this.message message;}public T getDate() {return date;}public void setDate(T date) {this.date date;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code code;}public String getMessage() {return message;}public void setMessage(String message) {this.message message;}Overridepublic String toString() {return JSONObject.toJSONString(this);} }最后就是使用响应包装类和状态码枚举类 来实现返回响应的包装了 GetMapping(/user/findAllUser) public ResponseListUser findAllUser() {logger.info(开始查询所有数据...);ListUser findAllUser new ArrayList();findAllUser.add(new User(张三, 18));findAllUser.add(new User(李四, 22));// 返回响应进行包装Response response new Response(findAllUser, ResponseCode.SUCCESS.code(), ResponseCode.SUCCESS.message());logger.info(response: {} n, response.toString());return response; }在浏览器中输入网址 http:// 127.0.0.1:8080/v1/api/u ser/findAllUser 然后点击回车得到如下数据 {code: 1200,date: [{age: 18,name: 张三},{age: 22,name: 李四}],message: 请求成功 }通过看这中实现响应包装的方式我们能发现什么问题吗 答代码很冗余需要在每个接口方法中都进行响应的包装使得接口方法包含了很多非业务逻辑代码 有没有版本进行优化下呢 en en 思考中。。。。。 啊自定义注解 拦截器可以实现呀 自定义注解实现接口响应包装 ①、首先创建一个进行响应包装的自定义注解 /*** Description: 标记方法返回值需要进行包装的 自定义注解**/ Target({ElementType.TYPE, ElementType.METHOD}) Retention(RetentionPolicy.RUNTIME) Documented public interface ResponseResult {}②、创建一个拦截器实现对请求的拦截看看请求的方法或类上是否使用了自定义的注解 /*** Description: 拦截器拦截请求判断请求的方法或类上是否使用了自定义的ResponseResult注解* 并在请求内设置是否使用了自定义注解的标志位属性**/ Component public class ResponseResultInterceptor implements HandlerInterceptor {/*** 标记位标记请求的controller类或方法上使用了到了自定义注解返回数据需要被包装*/public static final String RESPONSE_ANNOTATION RESPONSE_ANNOTATION;/*** 请求预处理判断是否使用了自定义注解*/Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {// 请求的接口方法if (handler instanceof HandlerMethod) {final HandlerMethod handlerMethod (HandlerMethod) handler;final Class? clazz handlerMethod.getBeanType();final Method method handlerMethod.getMethod();// 判断是否在类对象上加了注解if (clazz.isAnnotationPresent(ResponseResult.class)) {// 在请求中设置需要进行响应包装的属性标志在下面的ResponseBodyAdvice增强中进行处理request.setAttribute(RESPONSE_ANNOTATION, clazz.getAnnotation(ResponseResult.class));} else if (method.isAnnotationPresent(ResponseResult.class)) {// 在请求中设置需要进行响应包装的属性标志在下面的ResponseBodyAdvice增强中进行处理request.setAttribute(RESPONSE_ANNOTATION, method.getAnnotation(ResponseResult.class));}}return true;} }③、创建一个增强Controller实现对返回响应进行包装的增强处理 /*** Description: 对 返回响应 进行包装 的增强处理**/ ControllerAdvice public class ResponseResultHandler implements ResponseBodyAdviceObject {private final Logger logger LoggerFactory.getLogger(this.getClass());/*** 标记位标记请求的controller类或方法上使用了到了自定义注解返回数据需要被包装*/public static final String RESPONSE_ANNOTATION RESPONSE_ANNOTATION;/*** 请求中是否包含了 响应需要被包装的标记如果没有则直接返回不需要重写返回体*/Overridepublic boolean supports(MethodParameter methodParameter, Class? extends HttpMessageConverter? aClass) {ServletRequestAttributes ra (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest sr (HttpServletRequest) ra.getRequest();// 查询是否需要进行响应包装的标志ResponseResult responseResult (ResponseResult) sr.getAttribute(RESPONSE_ANNOTATION);return responseResult null ? false : true;}/*** 对 响应体 进行包装; 除此之外还可以对响应体进行统一的加密、签名等** param responseBody 请求的接口方法执行后得到返回值(返回响应)*/Overridepublic Object beforeBodyWrite(Object responseBody, MethodParameter methodParameter, MediaType mediaType, Class? extends HttpMessageConverter? aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {logger.info(返回响应 包装进行中。。。);Response response;// boolean类型时判断一些数据库新增、更新、删除的操作是否成功if (responseBody instanceof Boolean) {if ((Boolean) responseBody) {response new Response(responseBody, ResponseCode.SUCCESS.code(), ResponseCode.SUCCESS.message());} else {response new Response(responseBody, ResponseCode.ERROR.code(), ResponseCode.ERROR.message());}} else {// 判断像查询一些返回数据的情况查询不到数据返回 null;if (null ! responseBody) {response new Response(responseBody, ResponseCode.SUCCESS.code(), ResponseCode.SUCCESS.message());} else {response new Response(responseBody, ResponseCode.ERROR.code(), ResponseCode.ERROR.message());}}return response;} }④、最后在 Controller 中使用上我们的自定义注解在 Controller 类上或者 方法上使用ResponseResult自定义注解即可 在浏览器中输入网址 http://127.0.0.1:8080/v1/api/user/findAllUserByAnnotation 进行查看 // 自定义注解用在了方法上 ResponseResult GetMapping(/user/findAllUserByAnnotation) public ListUser findAllUserByAnnotation() {logger.info(开始查询所有数据...);ListUser findAllUser new ArrayList();findAllUser.add(new User(张三, 18));findAllUser.add(new User(李四, 22));logger.info(使用 ResponseResult 自定义注解进行响应的包装使controller代码更加简介);return findAllUser; }至此我们的接口返回响应包装自定义注解实现设计完成看看代码是不是又简洁又优雅呢。 总结本文针对此方案只是进行了简单的实现如果有兴趣的朋友可以进行更好的优化。 场景二自定义注解 AOP 实现优雅的使用分布式锁 分布式锁的最常见的使用流程 先看看最为常见的分布式锁使用方式的实现然后再聊聊自定义注解怎么优雅的实现分布式锁的使用。 普通的分布式锁使用方式 通过上面的代码可以得到一个信息如果有很多方法中需要使用分布式锁那么每个方法中都必须有获取分布式锁和释放分布式锁的代码这样一来就会出现代码冗余 那有什么好的解决方案吗 自定义注解使代码变得更加简洁、优雅 自定义注解优雅的使用分布式锁 ①、首先实现一个标记分布式锁使用的自定义注解 /*** Description: 获取redis分布式锁 注解**/ Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) Documented public interface GetDistributedLock {// 分布式锁 keyString lockKey();// 分布式锁 value默认为 lockValueString lockValue() default lockValue;// 过期时间默认为 300秒int expireTime() default 300;}②、定义一个切面在切面中对使用了 GetDistributedLock 自定义注解的方法进行环绕增强通知 /*** Description: 自定义注解结合AOP切面编程优雅的使用分布式锁**/ Component Aspect public class DistributedLockAspect {private final Logger logger LoggerFactory.getLogger(this.getClass());AutowiredRedisService redisService;/*** Around 环绕增强通知** param joinPoint 连接点所有方法都属于连接点但是当某些方法上使用了GetDistributedLock自定义注解时* 则其将连接点变为了切点然后在切点上织入额外的增强处理切点和其相应的增强处理构成了切面Aspect 。*/Around(value annotation(com.lyl.annotation.GetDistributedLock))public Boolean handlerDistributedLock(ProceedingJoinPoint joinPoint) {// 通过反射获取自定义注解对象GetDistributedLock getDistributedLock ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(GetDistributedLock.class);// 获取自定义注解对象中的属性值String lockKey getDistributedLock.lockKey();String LockValue getDistributedLock.lockValue();int expireTime getDistributedLock.expireTime();if (redisService.tryGetDistributedLock(lockKey, LockValue, expireTime)) {// 获取分布式锁成功后继续执行业务逻辑try {return (boolean) joinPoint.proceed();} catch (Throwable throwable) {logger.error(业务逻辑执行失败。, throwable);} finally {// 最终保证分布式锁的释放redisService.releaseDistributedLock(lockKey, LockValue);}}return false;}}③、最后在 Controller 中的方法上使用 GetDistributedLock 自定义注解即可当某个方法上使用了 自定义注解那么这个方法就相当于一个切点那么就会对这个方法做环绕方法执行前和方法执行后增强处理 在浏览器中输入网址 http://127.0.0.1:8080/v1/api/user/getDistributedLock 回车后触发方法执行 // 自定义注解的使用 GetDistributedLock(lockKey userLock) GetMapping(/user/getDistributedLock) public boolean getUserDistributedLock() {logger.info(获取分布式锁...);// 写具体的业务逻辑return true; }通过自定义注解的方式可以看到代码变得更加简洁、优雅。 场景三自定义注解 AOP 实现日志的打印 先看看最为常见的日志打印的方式然后再聊聊自定义注解怎么优雅的实现日志的打印。 普通日志的打印方式 通过看上面的代码可以知道如果每个方法都需要打印下日志那将会存在大量的冗余代码 自定义注解实现日志打印 ①、首先创建一个标记日志打印的自定义注解 /*** Description: 自定义注解实现日志打印**/ Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) Documented public interface PrintLog {}②、定义一个切面在切面中对使用了 PrintLog 自定义注解的方法进行环绕增强通知 /*** Description: 自定义注解结合AOP切面编程优雅的实现日志打印**/ Component Aspect public class PrintLogAspect {private final Logger logger LoggerFactory.getLogger(this.getClass());/*** Around 环绕增强通知** param joinPoint 连接点所有方法都属于连接点但是当某些方法上使用了PrintLog自定义注解时* 则其将连接点变为了切点然后在切点上织入额外的增强处理切点和其相应的增强处理构成了切面Aspect 。*/Around(value annotation(com.lyl.annotation.PrintLog))public Object handlerPrintLog(ProceedingJoinPoint joinPoint) {// 获取方法的名称String methodName joinPoint.getSignature().getName();// 获取方法入参Object[] param joinPoint.getArgs();StringBuilder sb new StringBuilder();for (Object o : param) {sb.append(o ; );}logger.info(进入《{}》方法, 参数为: {}, methodName, sb.toString());Object object null;// 继续执行方法try {object joinPoint.proceed();} catch (Throwable throwable) {logger.error(打印日志处理error。。, throwable);}logger.info({} 方法执行结束。。, methodName);return object;}}③、最后在 Controller 中的方法上使用 PrintLog 自定义注解即可当某个方法上使用了 自定义注解那么这个方法就相当于一个切点那么就会对这个方法做环绕方法执行前和方法执行后增强处理 PrintLog GetMapping(value /user/findUserNameById/{id}, produces application/json;charsetutf-8) public String findUserNameById(PathVariable(id) int id) {// 模拟根据id查询用户名String userName 张三三;return userName; }④、在浏览器中输入网址 http://127.0.0.1:8080/v1/api/user/findUserNameById/66 回车后触发方法执行发现控制台打印了日志 进入《findUserNameById》方法, 参数为: 66; findUserNameById 方法执行结束。。
http://www.zqtcl.cn/news/377494/

相关文章:

  • 做海报图片的网站营销软件
  • 能先做网站再绑定域名吗石家庄公司建设网站
  • 设计网站的收费图是怎么做的公司网站简介怎么做
  • 医院网站案例结合七牛云做视频网站
  • wordpress数据库缓存插件aso优化吧
  • 网站二维码代码国贸汽车网站建设
  • 医疗网站建设多少钱信息查询类网站是怎么做的
  • 网站开发辅助工具搜索引擎推广实训
  • 如何用手机制作网站比价网站
  • 商城类网站备案四川全网推网络推广
  • 好设计购物网站wordpress 公网访问不了
  • 局域网网站建设需要什么条件wordpress文章列表高度
  • 长春怎样建网站?学服装设计培训机构
  • 怎么用织梦制作响应式布局网站阳江网红
  • 洛阳网站建站72建站网
  • 网站版权信息修改app开发公司资质
  • 用vs2015做网站教程天津红桥网站建设
  • 触屏网站开发四川住房建设厅网站
  • 百度商桥怎么接网站wordpress电影自动采集主题
  • 丽水做网站公司用vps建网站备案
  • 西安网站制作机构视频网站 备案
  • 北京城乡建设学校网站国内外贸网站建设公司
  • 万峰科技著.asp.net网站开发四酷全书电子工业出版社专业网站制作定制
  • 如何做好一个网站运营建公司网站的详细步骤
  • python开发做网站代理注册公司怎么样
  • 网站开发技术简介深圳市市场监督管理局官网
  • 有那种网站的浏览器wordpress调用当前分类文章
  • 电子商务网站推广论文网站规划思想方法有哪些内容
  • adsl做网站无锡免费网站制作
  • 怎么利用网站开发app免费软件库合集软件资料网站