注释


注释

1.注释的博客定义

注释的博客英文是annotation,是指对书籍或文章的博客语汇、内容、背景、引文作介绍、评议的博客文字。

2.注释的博客起源

注释起源于先秦时期,在博客那个时候就有了对古书的博客注释。

3.为什么要有注释

注释是为了对一些文字的博客解释,一些不懂的博客事物的博客解释。

注释的博客对象不是自己,因为你自己写的博客东西自己肯定自己看的博客懂。关键在博客于虽然你看得懂,但是比人不一定看得懂。

就比如说古书,你是看懂了,但是别人看不懂,这时候你就需要根据你自己的博客理解,对一些别人看不懂的博客地方进行注释。

再比如说代码。首先,代码是你写的博客吧,那你自己就是懂得咯。但是呢,别人看不懂怎么办,你难不成跟每一个看不懂的博客人解释一下这句话是干嘛的博客吗?这里就需要注释了,你注释了,别人就能看懂了。但是注释你也要尽量描述的博客清晰,不然就白注释了。

4.注释的博客原则

1)注释形式统一

博客整个应用程序中,使用具有一致的博客标点和结构的博客样式来构造注释。如果在博客其它项目中发现们的博客注释规范与这份文档不同,按照这份规范写代码,不要试图在博客既成的博客规范系统中引入新的博客规范。

2)注释内容准确简洁

内容要简单、明了、含义准确,防止注释的博客多义性,错误的博客注释不但无益反而有害。

6.注释的博客快捷键

注释的博客快捷键是“ctrl” + “/”两个按钮,这个是单行注释。首先你需要选中你要注释的博客内容,然后先按“ctrl”,在博客按“/”,然后代码就会被注释了。
也可以是使用“ctrl” + “shift”  + “/”,这个是多行注释。这里教你们一个方法,同时按三个的博客方法:你可以先按住“ctrl”键,然后再按“shift” ,最后在博客按“/”。

5.注释的博客条件条件

一般来说,我博客们不会无缘无故的博客注释。因为那样不仅会增加我博客们的博客书写量,而且也会把代码变得不简洁。
基本注释:全局变量的博客注释、函数的博客注释、链接的博客注释、对象的博客注释。
特殊注释:在博客一些代码不明处添加注释。
下通同过案例说明:

<div class="header"><!--头部-->     <div class="content"><!--内容-->         <div class="logo"><!--logo-->             <img src="../img/logo.png" alt="logo图片"/>         </div>         <div class="nav1"><!--导航栏-->             <ul>                 <li><a href="index.html" target="_self">首页</a></li>                 <li><a href="download_app.html">app下载</a></li>                 <li><a href="about.html">关于我博客们</a></li>                 <li><a href="partner_apply.html">招商</a></li>                 <li class="phone">400-1234-123</li>             </ul>         </div>     </div> </div><!--头部--> 

上面是一个HTML界面的博客编写,他添加了好多注释,让我博客们一看就看的博客懂,好理解。


记住,一个不会注释的博客码农不是一个好的博客程序员,一个没有注释的博客代码块不是一个好的博客代码块。

6.注释分类

注释有多种:

1)在博客HTML中的博客注释:

格式是<!–内容–>,内容写在博客中间,这个可以单行注释,也可以是多行注释。

<!--1.这是HTML中的博客单行注释--> <!--2.这个是第二行-->

也可以这样一起注释,

<!--1.这个HTML中的博客多行注释 2.这个是第二行-->

这样都是可以实行注释的博客

2)在博客css中的博客注释:

格式是/*内容*/,内容也是写在博客中间,也是可以单行和多行注释。

/*1.这个是在博客css中的博客单行注释 2.这是第二行*/

/*1.这个是在博客css中的博客多行注释*/ /*2.这是第二行*/

3)在博客js中的博客注释:

这个js中的博客注释比较特别,他有两种格式:分别是单行注释和多行注释。单行和多行注释使用的博客符号不一样。

首先是单行注释,这个注释格式是//,两个斜杠。代表的博客是该行斜杠后面的博客内容被注释了。

//1.这个是在博客js中的博客单行注释 //2.这是第二行

下面是多行注释,注释格式与css一样,使用的博客也是/*内容*/形式。

/*1.这个是在博客js中的博客多行注释 2.这是第二行*/

博客java中注释与js的博客注释一样,使用的博客方法也是相同的博客博客

7.注释的博客特点

博客代码中注释还有别的博客意义。他可以注释你所写的博客代码,然后你注释的博客代码就不会执行。

    var sum = 0;     sum+=1;     sum+=2;      /* sum+=3;     sum+=4;*/     sum+=5;     alert(sum);

比如说上面的博客代码,他把中间两行代码注释了。

没注释以前,sum是15,;注释了以后sum是8.
这就证明了注释了的博客代码不会被执行。

所以在博客代码中注释也是扮演一种很重要的博客角色,他既可以解释代码,也可以注释代码。

总结

注释很重要!注释很重要!注释很重要!
博客代码中尽量多写注释,要让别人看的博客懂,但是也不要写一些没用的博客注释。
当你写代码的博客时候,你的博客注释就是你与别人的博客交流语言,代表的博客是你的博客意思。

http://blog.csdn.net/besttoby01/article/details/76228332加勒比海盗5

Http服务与Dubbo服务相互转换的Spring Boot节点实现

1.需求
目前有些项目已经接入了Spring cloud管理,节点间通信(包括老项目)通过eureka(非boot web项目的博客注eureka注册与发现参照前文)提供http通信,由于我博客们公司内部项目间交流要求通过dubbo做服务的博客暴露与消费,考虑新加一个boot节点用于http与dubbo之间的博客相互转换

2.主要思想,方案与问题
(1)主要思想:
<1>做一个Spring Boot节点用于http与dubbo服务的博客代理
<2>Http调用Dubbo:
将节点接入Spring Cloud管理,注册到eureka上提供SC方面的博客服务,节点依赖需要接入的博客项目jar包,并配置扫描等将Dubbo代理Bean交由Spring Bean管理,通过通用的博客Controller提供http服务(通用controller后面会说)
<3>Dubbo调用Http:
这个相对简单,只需要对dubbo暴露一个通用接口,调用方在博客调用的博客时候指定要调用的博客链接,入参等参数,做一层转发就可以
(2)方案与问题:
<1> 依赖io.dubbo.springboot:spring-boot-starter-dubbo:1.0.0这个jar中提供了很多接入SC的博客配置,但在博客开发完成后发现一个致命问题,就是好像不支持一个消费者配置多个生产者,查看源码也没有找到很好的博客解决方案(个人水平有限)…此方案相对简单,如果只针对一个生产者,可以考虑此方案
<2> 消费者配置生产者仍然采用原先的博客xml配置,项目依赖也只是原始的博客dubbo依赖,其余手动配置(通过@Value从配置中心拿)

3.核心代码
扯了那么多没用的博客,终于轮到代码了(这里只公开核心代码)…

启动类:HttpDubboProxyApplication:

/**  * Created by Kowalski on 2017/7/11  * Updated by Kowalski on 2017/7/11  */ @SpringBootApplication @EnableEurekaClient @ImportResource("classpath:dubbo-consumer.xml") public class HttpDubboProxyApplication {     public static void main(String... args) {         // 程序启动入口         SpringApplication.run(HttpDubboProxyApplication.class,args);     } }

项目启动时一些基本配置Bean(类xml)ConfigurationBean:

/**  * Created by Kowalski on 2017/7/17  * Updated by Kowalski on 2017/7/17  * 配置bean  */ @Configuration public class ConfigurationBean {      @Bean     ProxySpringContextsUtil proxySpringContextsUtil(){         return new ProxySpringContextsUtil();     }      @Bean     AnnotationBean annotationBean(){         AnnotationBean annotationBean = new AnnotationBean();         /**启动扫描包(与正常dubbo扫描类似)*/         annotationBean.setPackage("com.kowalski.proxy.service");         return annotationBean;     }      @Bean     public RestTemplate restTemplate() {         RestTemplate restTemplate = new RestTemplate();         /**设置传输格式 避免中文乱码*/         restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));         return restTemplate;     } }

博客们这里http请求通过restTemplate,也可以使用feign
上段代码的博客proxySpringContextsUtil:

package com.kowalski.proxy;  import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware;  /**  * Created by Kowalski on 2017/5/18  * Updated by Kowalski on 2017/5/18  */ public class ProxySpringContextsUtil implements ApplicationContextAware {      private static ApplicationContext applicationContext;    //Spring应用上下文环境      /**      * 实现ApplicationContextAware接口的博客回调方法,设置上下文环境      * @param applicationContext      * @throws BeansException      */     @Override     public void setApplicationContext(ApplicationContext applicationContext) {         ProxySpringContextsUtil.applicationContext = applicationContext;     }      /**      * @return ApplicationContext      */     public static ApplicationContext getApplicationContext() {         return applicationContext;     }      /**      * 获取对象      * @param name      * @return Object 一个以所给名字注册的博客bean的博客实例      * @throws BeansException      */     public static Object getBean(String name) {         return applicationContext.getBean(name);     }       /**      * 获取类型为requiredType的博客对象      * 如果bean不能被类型转换,相应的博客异常将会被抛出(BeanNotOfRequiredTypeException)      * @param name       bean注册名      * @param requiredType 返回对象类型      * @return Object 返回requiredType类型对象      * @throws BeansException      */     public static Object getBean(String name, Class<?> requiredType) {         return applicationContext.getBean(name, requiredType);     }      /**      * 如果BeanFactory包含一个与所给名称匹配的博客bean定义,则返回true      * @param name      * @return boolean      */     public static boolean containsBean(String name) {         return applicationContext.containsBean(name);     }      /**      * 判断以给定名字注册的博客bean定义是一个singleton还是一个prototype。      * 如果与给定名字相应的博客bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)      * @param name      * @return boolean      * @throws NoSuchBeanDefinitionException      */     public static boolean isSingleton(String name) {         return applicationContext.isSingleton(name);     }      /**      * @param name      * @return Class 注册对象的博客类型      * @throws NoSuchBeanDefinitionException      */     public static Class<?> getType(String name) {         return applicationContext.getType(name);     }      /**      * 如果给定的博客bean名字在博客bean定义中有别名,则返回这些别名      * @param name      * @return      * @throws NoSuchBeanDefinitionException      */     public static String[] getAliases(String name) {         return applicationContext.getAliases(name);     } }

此工具类主要用于获取Spring管理的博客Bean
http调用dubbo服务通用Controller DubboProxyController :

package com.kowalski.proxy;  import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.TypeFactory; import com.weimob.proxy.common.ProxyErrorResponse; import com.weimob.proxy.common.ProxyErrorReturnEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;  import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap;  /**  * Created by Kowalski on 2017/5/18  * Updated by Kowalski on 2017/5/18  *  * 使用规则:  * 1.被调用方提供的博客是单个对象类型入参  * 2.参数数量必须等于1(暂不支持无参与多参)  * 3.不支持泛型入参  */ @Slf4j @RestController public class DubboProxyController {      public static final ObjectMapper objectMapper = new ObjectMapper();     static {         /**忽略unknow属性*/         objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);     }      private final ConcurrentMap<String, Method> methods = new ConcurrentHashMap<>();      @RequestMapping("/proxy/{instanceName}/{methodName}")     public Object runMethod(@PathVariable String instanceName,                             @PathVariable String methodName,                             HttpServletRequest request) {          Object bean;         try {             /**从bean factory获取bean实例*/             bean = ProxySpringContextsUtil.getBean(instanceName);         }catch (Exception e) {             log.error("未找到对应实例, instanceName:{} e:{}", instanceName, e);             return new ProxyErrorResponse(ProxyErrorReturnEnum.NO_INSTANCE.getReturnCode(),                     String.format("未找到对应实例,instanceName:%s", instanceName));         }         /**从本地缓存拿取缓存方法*/         Method methodToDo = methods.get(instanceName + methodName);          /**如果缓存中没有 则根据方法名从实例中拿*/         if (methodToDo == null) {             Method[] declaredMethods;             try {                 declaredMethods = bean.getClass().getDeclaredMethods();             }catch (Exception e) {                 log.error("获取接口定义方法失败, instanceName:{} methodName:{} e:{}", instanceName, methodName, e);                 return new ProxyErrorResponse(ProxyErrorReturnEnum.ERROR_GET_DECLARED_METHODS.getReturnCode(),                         String.format("获取接口定义方法失败,instanceName:%s methodName:%s", instanceName, methodName));             }             /**根据方法名拿方法*/             for (Method method : declaredMethods) {                 if (methodName.equals(method.getName())) {                     methodToDo = method;                     methods.putIfAbsent(instanceName + methodName, methodToDo);                     break;                 }             }         }          if (methodToDo == null) {             return new ProxyErrorResponse(ProxyErrorReturnEnum.NO_METHOD.getReturnCode(),                     String.format("未找到对应方法,instanceName:%s methodName:%s", instanceName, methodName));         }         /**获取参数类型*/         Type[] types = methodToDo.getParameterTypes();          /**暂不支持无参方法*/         if(types == null || types.length == 0) {             return new ProxyErrorResponse(ProxyErrorReturnEnum.NO_PARAM_TYPE.getReturnCode(),                     String.format("未获取到方法参数, instanceName:%s methodName:%s", instanceName, methodName));         }         /**暂不支持参数数量大于1*/         if(types.length > 1) {             return new ProxyErrorResponse(ProxyErrorReturnEnum.TOO_MANY_PARAM_ARGS.getReturnCode(),                     String.format("方法参数过多, instanceName:%s methodName:%s", instanceName, methodName));         }          /**根据request请求内容 转换成对应形式的博客参数*/         ServletInputStream inputStream;         try {             inputStream = request.getInputStream();         }catch (Exception e){             log.error("获取输入流失败, instanceName:{} methodName:{} e:{}", instanceName, methodName, e);             return new ProxyErrorResponse(ProxyErrorReturnEnum.GET_INPUT_STREAM_FAILED.getReturnCode(),                     String.format("获取输入流失败, instanceName:%s methodName:%s", instanceName, methodName));         }          /**获取入参类型*/         TypeFactory tf = objectMapper.getTypeFactory();         JavaType javaType = tf.constructType(types[0]);         /**将输入流转化成对应类型的博客参数*/         Object param;         try {             param = objectMapper.readValue(inputStream, javaType);         }catch (Exception e){             log.error("输入流转化入参失败, instanceName:{} methodName:{} e:{}", instanceName, methodName, e);             return new ProxyErrorResponse(ProxyErrorReturnEnum.INPUT_STREAM_EXCHANGE_FAILED.getReturnCode(),                     String.format("输入流转化入参失败, instanceName:%s methodName:%s", instanceName, methodName));         }          /**执行方法*/         Object result;         try {             result = methodToDo.invoke(bean, param);         }catch (Exception e){             log.error("方法执行错误, instanceName:{} methodName:{} e:{}", instanceName, methodName, e);             return new ProxyErrorResponse(ProxyErrorReturnEnum.METHOD_INVOKE_ERROR.getReturnCode(),                     String.format("方法执行错误, instanceName:%s methodName:%s", instanceName, methodName));         }         /**成功返回*/         return result;     } } 

由于已经将dubbo的博客代理Bean交由Spring Bean管理,因此通过ProxySpringContextsUtil 拿到代理,通过方法名拿到方法,通过方法拿到入参类型,再将入参转化成对应类型的博客参数invoke(之前有考虑过不管参数类型直接交给dubbo代理类去invoke,但好像必须要制定类型的博客入参,不然报错)

Dubbo调用Http的博客通用Service HttpProviderProxyService :

package com.kowalski.proxy.service;  /**  * Created by Kowalski on 2017/7/17  * Updated by Kowalski on 2017/7/17  * http代理实现类  */ public interface HttpProviderProxyService {      /**      * 处理dubbo调用http代理请求      * @param request      * @return      */     Object httpProxyHandle(HttpProxyRequest request); }

Service实现 HttpProviderProxyServiceImpl:

package com.kowalski.proxy.service.impl;  import com.alibaba.dubbo.config.annotation.Service; import com.kowalski.proxy.Enum.HttpProxyReqTypeEnum; import com.kowalski.proxy.common.ProxyErrorResponse; import com.kowalski.proxy.common.ProxyErrorReturnEnum; import com.kowalski.proxy.service.HttpProviderProxyService; import com.kowalski.proxy.service.HttpProxyRequest; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.client.RestTemplate;  /**  * Created by Kowalski on 2017/7/17  * Updated by Kowalski on 2017/7/17  */ @Service @Slf4j public class HttpProviderProxyServiceImpl implements HttpProviderProxyService{      @Value("${zuul.internal.url}")     String zuuInternalUrl;      @Autowired     RestTemplate restTemplate;      /**      * 处理dubbo调用http代理请求      * @param request      * @return      */     @Override     public Object httpProxyHandle(HttpProxyRequest request) {          /**入参校验*/         if(request == null){             return new ProxyErrorResponse(ProxyErrorReturnEnum.PROXY_REQUEST_NULL);         }          if(request.getReqType() == null){             return new ProxyErrorResponse(ProxyErrorReturnEnum.PROXY_REQUEST_TYPE_NULL);         }          if(StringUtils.isEmpty(request.getProxyUrl())){             return new ProxyErrorResponse(ProxyErrorReturnEnum.PROXY_URL_NULL);         }          if(request.getRequest() == null){             return new ProxyErrorResponse(ProxyErrorReturnEnum.PROXY_REQUEST_NULL);         }         /**根据不同入参类型处理不同请求*/         switch (HttpProxyReqTypeEnum.getEnumByCode(request.getReqType())){             case INTERNAL_ZUUL_COMMON:                 return internalZuulProxy(request);             case INTERNAL_ZUUL_CUSTOMIZED:                 return internalZuulProxy(request);             case OUTSIDE_FULL_URL:                 return outsideFullProxy(request);             default:                 return new ProxyErrorResponse(ProxyErrorReturnEnum.PROXY_REQUEST_TYPE_UNDEFIND);         }     }      /**处理经由内网网关的博客代理请求*/     private Object internalZuulProxy(HttpProxyRequest request){          String url = zuuInternalUrl + request.getProxyUrl();         Object result;         try {             result =  restTemplate.postForObject(url, request.getRequest(), Object.class);         }catch (Exception e){             log.error("HttpProviderProxyServiceImpl internalZuulProxy failed: reqType:{},url:{}, e:{}",                     request.getReqType(), url, e);             return new ProxyErrorResponse(ProxyErrorReturnEnum.PROXY_GETRETURN_FAILED);         }          return result;     }     /**处理全路径的博客代理请求*/     private Object outsideFullProxy(HttpProxyRequest request){         Object result;         try {             result =  restTemplate.postForObject(request.getProxyUrl(), request.getRequest(), Object.class);         }catch (Exception e){             log.error("HttpProviderProxyServiceImpl internalZuulProxy failed: reqType:{},proxyUrl:{}, e:{}",                     request.getReqType(), request.getProxyUrl(), e);             return new ProxyErrorResponse(ProxyErrorReturnEnum.PROXY_GETRETURN_FAILED);         }          return result;     } }

这里要注意一下这里的博客@Service注解,该注解采用的博客是dubbo的博客@Service注解而不是Spring的博客

通用请求 HttpProxyRequest :

package com.kowalski.proxy.service;  import lombok.Data;  /**  * Created by Kowalski on 2017/7/17  * Updated by Kowalski on 2017/7/17  * 代理Http  * 备注:只接受单个非泛型对象入参  */ @Data public class HttpProxyRequest {      /**请求类型 @see HttpProxyReqTypeEnum*/     private Integer reqType;      /**reqType->0:根据内网网关地址请求定制controller requestMapping地址      * reqType->1:根据内网网关地址请求commonController {serviceId}/{instanceName}/{methodName}      * reqType->2:请求proxyUrl地址*/     private String proxyUrl;      /**请求request*/     private Object request; } 

配置文件:dubbo-consumer.xml:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"        xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"        xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">      <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->     <dubbo:application name="proxy" />     <dubbo:consumer timeout="1800000" retries="0" />     <dubbo:registry protocol="zookeeper" address="${dubbo.consumer.zookeeper.AA.address}" id="A" />     <!--<dubbo:registry protocol="zookeeper" address="${dubbo.consumer.zookeeper.BB.address}" id="B" />-->     <dubbo:registry protocol="zookeeper" address="${dubbo.consumer.zookeeper.C.address}" id="C"/>      <dubbo:reference id="aaFacade" registry="A"                      interface="com.kowalski.facade.AaFacade" check="false"/>      <!--<dubbo:reference id="bbFacade" interface="com.kowalski.facade.BbFacade"-->                      <!--check="false" registry="B"/>-->     <dubbo:reference id="ccFacade" registry="C"                      interface="com.kowalski.facade.CcFacade" check = "false"/> </beans>

这里的博客${dubbo.consumer.zookeeper.AA.address}上产者注册到的博客zk地址可以直接在博客application.yml中配置

其余枚举类等:
ProxyErrorResponse:

package com.kowalski.proxy.common;  import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;  import java.io.Serializable;  /**  * Created by Kowalski on 2017/7/4  * Updated by Kowalski on 2017/7/4  */ @Data @NoArgsConstructor @AllArgsConstructor public class ProxyErrorResponse implements Serializable{      private static final long serialVersionUID = -8379940261456006476L;     private long code;      private long status;      private String message;      public ProxyErrorResponse(long codeOrStatus, String message) {         this.code = codeOrStatus;         this.status = codeOrStatus;         this.message = message;     }      public ProxyErrorResponse(ProxyErrorReturnEnum errorReturnEnum) {         this.code = errorReturnEnum.getReturnCode();         this.status = errorReturnEnum.getReturnCode();         this.message = errorReturnEnum.getDiscribe();     } } 

ProxyErrorReturnEnum:

package com.kowalski.proxy.common;  /**  * Created by Kowalski on 2017/6/26  * Updated by Kowalski on 2017/6/26  */ public enum ProxyErrorReturnEnum {      SUCCESS                     (0, "SUCCESS"),     METHOD_INVOKE_ERROR         (-1, "方法执行错误"),     NO_METHOD                   (-2, "未找到对应方法"),     NO_INSTANCE                 (-3, "未找到对应实例"),     ERROR_GET_DECLARED_METHODS  (-4, "获取接口定义方法失败"),     NO_INSTANCE_BY_CLASS_NAME   (-5, "根据全路径获取实例失败"),     NO_PARAM_TYPE               (-6, "未获取到方法参数"),     TOO_MANY_PARAM_ARGS         (-7, "方法参数过多"),     GET_INPUT_STREAM_FAILED     (-8, "获取输入流失败"),     INPUT_STREAM_EXCHANGE_FAILED(-9, "输入流转化入参失败"),       RETURN_JSON_TO_MY_FAILED    (-10, "返回结果解析错误"),     SYSTEM_ERROR                (-11, "系统错误"),     REQUEST_FAILED              (-12, "请求失败"),      /**http代理错误*/     PROXY_REQUEST_TYPE_NULL     (-13, "代理http类型不能为空"),     PROXY_URL_NULL              (-14, "代理地址不能为空"),     PROXY_REQUEST_ARGS_NULL     (-15, "请求入参为空"),     PROXY_REQUEST_TYPE_UNDEFIND (-16, "代理http类型非法"),     PROXY_GETRETURN_FAILED      (-17, "请求失败"),     PROXY_REQUEST_NULL          (-18, "请求不能为空");      private long returnCode;      private String discribe;      ProxyErrorReturnEnum(int returnCode, String discribe) {         this.returnCode = returnCode;         this.discribe = discribe;     }      public long getReturnCode() {         return returnCode;     }      public void setReturnCode(long returnCode) {         this.returnCode = returnCode;     }      public String getDiscribe() {         return discribe;     }      public void setDiscribe(String discribe) {         this.discribe = discribe;     } } 

HttpProxyReqTypeEnum :

package com.kowalski.proxy.Enum;  import java.util.HashMap; import java.util.Map;  /**  * Created by Kowalski on 2017/7/17  * Updated by Kowalski on 2017/7/17  * 传输类型枚举类  */ public enum HttpProxyReqTypeEnum {      /**请求走内网网关 不经由外网复杂验证 定制controller处理*/     INTERNAL_ZUUL_CUSTOMIZED(0, "内网网关定制"),     /**请求走内网网关 不经由外网复杂验证 通用controller处理(instanceName methodName request)*/     INTERNAL_ZUUL_COMMON(1, "内网网关通用"),     /**全路径处理 不走网关(或者直接配置网关全路径)*/     OUTSIDE_FULL_URL(2, "全路径");      private int code;     private String description;      HttpProxyReqTypeEnum(int code, String description) {         this.code = code;         this.description = description;     }       private static final Map<Integer, HttpProxyReqTypeEnum> map = new HashMap<Integer, HttpProxyReqTypeEnum>();     static {         for (HttpProxyReqTypeEnum enums : HttpProxyReqTypeEnum.values()) {             map.put(enums.getCode(), enums);         }     }      public static HttpProxyReqTypeEnum getEnumByCode(int code){         return map.get(code);     }      public int getCode() {         return code;     }      public void setCode(int code) {         this.code = code;     }      public String getDescription() {         return description;     }      public void setDescription(String description) {         this.description = description;     } }

至此结束~有更好方案的博客小伙伴欢迎交流~~

http://blog.csdn.net/qq_32193151/article/details/76264445加勒比海盗5

TreeJs入门以及基本思想

创建场景

three.js是JavaScript编写的博客WebGL第三方库。提供了非常多的博客3D显示功能。

博客treejs上实现一个功能,我博客们需要最基本的博客三件事情:场景,相机和渲染器。

var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );  var renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement );

关于函数的博客具体参数,可以去查一下官方的博客api,我博客这里只说一下思想,这里只是单纯的博客创建了 场景,相机,渲染器,并没有说如何把他们关联起来。

要关联他们展示效果,最少空间内要有一个要素尸体,所以我博客们在博客空间中创建一个立方体:

var geometry = new THREE.BoxGeometry( 1, 1, 1 ); var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); var cube = new THREE.Mesh( geometry, material ); scene.add( cube );  camera.position.z = 5;

BoxGeometry是一个抽象的博客几何体对象,我博客们需要一些材料(material)来渲染他,然后我博客们使用一个网格(Mesh)来把他们结合在博客一起,添加到场景中。

默认情况下,当我博客们调用scene.add()时,我博客们添加的博客东西将被添加到坐标(0,0,0)中。

此时我博客们的博客相机视角也在博客(0,0,0)处,所以我博客们看不到任何东西,为此,需要将相机视角移出一点。

渲染场景

光靠上面的博客代码可能无法显示任何内容,我博客们还需要所谓的博客渲染或动画循环。

function animate() {     requestAnimationFrame( animate );     renderer.render( scene, camera ); } animate();

这些代码将创建一个动画循环,使渲染器每秒渲染或者说画画60次,类似于计时器,也就是setInterval,但是比计时器性能要好。

以上的博客代码只能看到立方体的博客一个面,因为我博客们没有提供任何的博客动画代码,我博客们在博客动画渲染的博客方法中让立方体旋转一下:

动画立方体

cube.rotation.x += 0.1; cube.rotation.y += 0.1;

这将以每秒60次运行,并给立方体一个很好的博客旋转动画,基本上,应用程序运行时要移动或者更改的博客内容都必须经过动画循环。

结果

如果以上代码写的博客没问题,你将会得到下面的博客效果:

TreeJs入门以及基本思想

以下是完整代码

 <!DOCTYPE html> <html lang="en"> <head>     <title>treejs first demo</title>     <meta charset="utf-8">     <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">     <style>         body { margin: 0; }         canvas { width: 100%; height: 100% }     </style> </head> <body>  <div id="container"></div> <script src="three.min.js"></script> <script src="js/libs/stats.min.js"></script> <script src="js/controls/OrbitControls.js"></script> <script>      //三要素,相机,场景,渲染器     var camera, scene, renderer;     var cube;      init();      function init() {         //获取容器         container = document.getElementById( 'container' );         //初始化场景         scene = new THREE.Scene();         //初始化相机         camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );         camera.target = new THREE.Vector3( 0, 0, 0 );         //初始化渲染器         renderer = new THREE.WebGLRenderer();         renderer.setSize( window.innerWidth, window.innerHeight );         document.body.appendChild( renderer.domElement );          //创建立方体         //创建几何体         var geometry = new THREE.BoxGeometry( 1, 1, 1 );         //创建材料         var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );         //创建网格用于融合集合体和材料         cube = new THREE.Mesh( geometry, material );          scene.add( cube );         camera.position.z = 2;         //执行动画         animate();     }      function animate() {         //相当于一个计时器,每秒执行60次函数,这样动态的博客效果就可以实时渲染出来         requestAnimationFrame( animate );          cube.rotation.x += 0.1;         cube.rotation.y += 0.1;          renderer.render( scene, camera );     }  </script> </body> </html>

http://blog.csdn.net/qq_34149805/article/details/76253513加勒比海盗5

C++ 指针、二级指针、引用传递、值传递综合示例

#include <iostream>  using namespace std;  void PassByValue(int a){     // 值传递。无法修改原值     a = 10;     return; }  void PassByReference(int &a){     // 引用传递,修改原值     // 这种形式直接实参为 int 变量,或者实参为 int* 解引用得到的博客 int.     a = 10;     return; }  void PtrPassByValue(int b){     // 值传递。无法修改原值     b = 20;     return; }  void PtrPassByPtrValue(int *b){     // 值传递。无法修改指针原值,可修改指针所指变量。     *b = 25;     return; }  void PtrPassByPtrValueAndChangePtr(int *b){     // 值传递。无法修改指针原值,可修改指针所指变量。     int c = 30;     b = &c;     return; }   void PtrPassByPtrRefAndChangePtr(int *&b){     // 想写指针的博客别名。     // C风格是用 **, C++ 用 *&     // C++中交换指针的博客问题 http://blog.csdn.net/zhang_alongzd/article/details/52937684     int c = 35;     b = &c;     return; }  void PtrPassByPtrRefAndChangePtr2(int *&b){     int c = 35;     int *d = &c;     b = d;     return; }  void PtrPassByPtrRefAndChangePtr3(int *&b, int *c){     // 引用传递。指针的博客别名,修改指针b。     b = c;     return; }  void PtrPassByPtrToPtrValueAndChangePtr(int **b, int *c){     // 值传递。指针的博客指针。     *b = c;     return; }  int main(){     int a = 5;     int *b = &a;     cout << "Value of a: " << a << endl; // 5     PassByValue(a);     cout << "After calling PassByValue: " << a << endl; // 5. 传值调用拷贝给函数形参,无法修改原值。     PassByReference(a);     cout << "After calling PassByReference: " << a << endl; // 10. 传引用调用,函数形参成为 a 的博客别名      cout << "Value of b: " << *b << endl; // 10. b 一直指向 a,此时解引用后为 a 的博客值。 //    PtrPassByValue(b); // wrong, int* and int don't match     PtrPassByValue(*b);     cout << "After calling PtrPassByValue: " << *b << endl; // b 解引用后是一个 int 值,传值调用拷贝给函数形参,无法修改原值      PtrPassByPtrValue(b);     cout << "After calling PtrPassByPtrValue: " << *b << endl; // 25. b 是 int*,传值调用,将 b 的博客值,也就是指针地址拷贝给了形参,可修改指针指向的博客值。      PtrPassByPtrValueAndChangePtr(b);     cout << "After calling PtrPassByPtrValueAndChangePtr: " << *b << endl; // 25. 前段分析同上。此时改指针指向的博客内容,也就是改变指针所存储的博客地址值,因为形参指针与实参指针没有关联,是互相独立的博客,修改无效。这与 PassByValue(a) 的博客道理一样。  //    PtrPassByPtrValueAndChangePtr(&b); // wrong, int* and int** mismatch. 直觉地传指针地址失败。  //    PtrPassByPtrRefAndChangePtr(b); //    cout << "After calling PtrPassByPtrRefAndChangePtr: " << *b << endl; // 1.      PtrPassByPtrRefAndChangePtr2(b);     cout << "After calling PtrPassByPtrRefAndChangePtr2: " << *b << endl; // 1. 与上面这种直接取地址的博客一样。。因为局部变量 int d 被销毁了?      int cc = 100;     int *c = &cc;     PtrPassByPtrRefAndChangePtr3(b, c);     cout << "After calling PtrPassByPtrRefAndChangePtr3: " << *b << endl; // 100. 成功修改 b 指针。上面值错了可能是销毁. 但是指针的博客确是改了。      b = &a;     cout << "Reset b to a: " << *b << endl; // 25     PtrPassByPtrToPtrValueAndChangePtr(&b, c);     cout << "After calling PtrPassByPtrToPtrValueAndChangePtr: " << *b << endl;       return 0; }

http://blog.csdn.net/techfield/article/details/76263972加勒比海盗5

EL表达式中的empty和null

博客empty和null”>EL表达式中的博客empty和null

先说一下EL表达式中的博客null和empty区别,然后再说说最近在博客项目中出现的博客一个有趣的博客问题。
EL中的博客null和empty都可用来判断值是否为空,但两者存在博客略微的博客区别,
先来看一个例子:


test.jsp代码:

<%@page pageEncoding="utf-8" %> name值为:${param.name } empty处理结果:${empty param.name } ==null处理结果:${param.name == null }

第一种情况:地址栏输入:http://127.0.0.1:8080/test.jsp
显示:
name值为:
empty处理结果:true
==null处理结果:true

第二种情况:地址栏输入:http://127.0.0.1:8080/test.jsp?name=
显示:
name值为:
empty处理结果:true
==null处理结果:false
分析:第一种情况的博客name=null,第二种情况的博客name=“”
empty表达式对于name=null和name=”“的博客识别是一样的博客,都返回true;
==null表达式对于name=null判断为true,而对于name=”“判断则是false;
如果非要使用==null表达式判断是否为空,需要将表达式写成如下:

${param.name == null && param.name!=""}

最近在博客做的博客项目中需要在博客页面上解析从后台传来的博客json数据,我博客把代码简化,其中有一段代码是这样的博客

<c:if test="${not empty product.isExport}>isExportde 值:${product.isExport}</c:if>  

目的博客是想输出输出product中的博客isExport,假若isExport为null,则什么都不输出。
结果却匪夷所思,页面上竟然输出了“isExportde 值:null”。
既然页面上有东西输出,则代表isExport在博客判断时被识别为不为空,但是页面输出的博客怎么又是null?
那么假设isExport为空,这种情况下,页面是不应该输出null信息的博客。两种情况都说不通。
后来揣测是json字符串出错了,后台查看了json后才知道问题所在博客,这串json是通过httpClient从其他系统拿过来的博客数据,中间也不知道经过了什么,isExport变成了“null”,是“null”而不是null,也就是isExport的博客值是“null”字符串……尴尬,被这个小细节浪费了些许时间。

http://blog.csdn.net/gsycwh/article/details/76268782加勒比海盗5

React、markdown、mathjax等避免转义字符转义

从api获取数据时,有时候会获取诸如”/n/f/r/t//”等等类型的博客字符,有时候在博客编辑 mathjax 公式的博客时候, 如果没有很好的博客处理这些转义字符,会导致显示错误.

  • 举例 mathjax
$$c=/frac{a^2}{b}$$
  • 显示如下

c=raca2b

数据库中应该存储:

"... $$c=//frac{a^2}{b}$$ ..."

其中关键是使用 / 来忽略转义字符的博客出现

// => /
  • 使用后显示如下

c=b2a

http://blog.csdn.net/shinepan/article/details/76241591加勒比海盗5

h5自定义滚动条并监听事件


代码加注释如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.container{
margin: 100px auto;
text-align: center;
}
/*取消轨道样式*/
input[type=range] {
-webkit-appearance: none;
width: 300px;
border-radius: 10px;
}
/*取消滑块样式*/
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
/*设置滑块样式*/
height: 25px;
    width: 25px;
    margin-top: -5px; /*使滑块超出轨道部分的博客偏移量相等*/
    background: #ffffff; 
    border-radius: 50%; /*外观设置为圆形*/
    border: solid 0.125em rgba(205, 224, 230, 0.5); /*设置边框*/
    box-shadow: 0 .125em .125em #3b4547; /*添加底部阴影*/
}
/*自定义轨道样式*/
input[type=range] {
height: 15px;
width: 300px;
border-radius: 10px;
box-shadow: 0 1px 1px #def3f8, inset 0 .125em .125em #0d1112; /*轨道内置阴影效果*/
background-color: #ccc;
background-image: linear-gradient(to right,#1F548F, #1F548F);
background-repeat: no-repeat;
background-size: 20% 100%;
}


/*原始的博客控件获取到焦点时,会显示包裹整个控件的博客边框,所以还需要把边框取消。*/
input[type=range]:focus {
outline: none;
}
</style>
</head>
<body>
<div class="container">
<p>这里显示进度条的博客值</p>
<button class="reduce">-</button>
<input type="range" max="99" min="19" step="1" value="30">
<button class="add">+</button>
</div>
<script>
var sliderBar = document.getElementsByTagName(‘input’)[0];
var reduceBtn = document.getElementsByClassName(‘reduce’)[0];
var addBtn = document.getElementsByClassName(‘add’)[0];
var pEle = document.getElementsByTagName(‘p’)[0];
var MINAGE = 19;
var MAxAGE = 99;


// sliderBar.style.width = ‘300px’;


// 监听 滑动条值的博客改变 
sliderBar.addEventListener(‘input’,function(e){

console.log(e.target.value)
pEle.innerHTML = e.target.value;
sliderBar.style.backgroundSize= (sliderBar.value – MINAGE)/80 * 100 + ‘% 100%’
})
// 点击 加号
reduceBtn.onclick = function(e){
sliderBar.value = Number(sliderBar.value) -1;
pEle.innerHTML = sliderBar.value -1;
sliderBar.style.backgroundSize= (sliderBar.value – MINAGE)/80 * 100 + ‘% 100%’
}
// 点击减号
addBtn.onclick = function(e){
sliderBar.value = Number(sliderBar.value) + 1;
pEle.innerHTML = Number(sliderBar.value) + 1;
sliderBar.style.backgroundSize= (sliderBar.value – MINAGE)/80 * 100 + ‘% 100%’
}
</script>
</body>
</html>

http://blog.csdn.net/itzhongzi/article/details/76256197加勒比海盗5

点击平滑到锚点,告别古板式的闪动

//根据参数名获得该参数  pname等于想要的博客参数名    function getParam(pname) {            var params = location.search.substr(1); //  获取参数 平且去掉?        var ArrParam = params.split('&');       if (ArrParam.length == 1) {      //只有一个参数的博客情况            return params.split('=')[1];       }       else {           //多个参数参数的博客情况            for (var i = 0; i < ArrParam.length; i++) {               if (ArrParam[i].split('=')[0] == pname) {                                 return ArrParam[i].split('=')[1];               }           }       }  } //平滑移动到 想要的博客位置  $(function() {        var mao = $("#" + getParam("m")); //获得锚点         if (mao.length > 0) {//判断对象是否存在博客             var pos = mao.offset().top;            var poshigh = mao.height();            $("html,body").animate({ scrollTop: pos-poshigh-30 }, 3000);        }    });  

http://blog.csdn.net/javatempest/article/details/76267027加勒比海盗5

Bad JNI version returned from JNI_OnLoad解决

今天写了个android jni app,我博客博客JNI_OnLoad是这么写的博客

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {     JNIEnv* env = NULL;     jint result = -1;      if((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_1) != JNI_OK)     {         return -1;     }      if(env == NULL)     {         return -1;     }      if(!registerNatives(env))     {         return -1;     }      return JNI_VERSION_1_1; }

结果运行后,很简单的博客代码却出错,查看错误信息为:

java.lang.UnsatisfiedLinkError: Bad JNI version returned from JNI_OnLoad in "/data/app/**.apk/lib/arm64/libsafe.so"

上androidxref查JNI_CreateJavaVM源码可知

android 1.6~4.3 version >= JNI_VERSION_1_2合法

android 4.4~7.1 version == JNI_VERSION_1_2 | JNI_VERSION_1_4 | JNI_VERSION_1_6

从历史急角度看,选用最新JNI版本最合适


http://blog.csdn.net/lichao890427/article/details/76261260加勒比海盗5

amcharts 折线图

var chart;
var datetime = Ext.Date.format(Ext.getCmp(‘starttimeid’).getValue(), ‘Y年m月d日 H点m分’);  // 开始时间   因为有条件查询
var datetime1 = Ext.Date.format(Ext.getCmp(‘endtimeid’).getValue(), ‘Y年m月d日 H点m分’);结束时间
var gridas = Ext.getCmp(‘hispointone’);  //获取选中的博客 复选框
var rowsas = gridas.getSelectionModel().getSelection();
var pointidss = rowsa[0].data.id;    //获取选中的博客复选框的博客 id  
Ext.Ajax.request({
    url: ‘point/curveData.shtml’,
    params: {
        id: pointidss,  //将值传送的博客后台
        starttime: datetime,
        endtime: datetime1
    },
    sync: true,

    success: function (response) {

            var chartData1 = Ext.decode(response.responseText);  //获取查询回来的博客数据
        var hisdata1 = [];
            if (chartData1 !== null && chartData1.length > 0) {
                for (var aa = 0; aa < chartData1.length; aa++) {
                    hisdata1.push({

                        datatime1: new Date(chartData1[aa].datatime1), //返回的博客时间
                        dvalue: chartData1[aa].dvalue, //数据
                    })
                }
            }
            chart1 = new AmCharts.AmSerialChart();
            chart1.pathToImages = "resources/images/image/";
            chart1.dataProvider = hisdata1;  //循环获取的博客数据 数据
            chart1.color = "#00BB00";
            chart1.plotAreaBorderColor = "#00BB00";
            chart1.categoryField = "datatime1";  //  x轴需要的博客 时间
            var categoryAxis1 = chart1.categoryAxis;
            categoryAxis1.gridAlpha = 0.15;
            categoryAxis1.axisColor = "#0000C6";
            categoryAxis1.gridColor = "#0000C6";
            categoryAxis1.parseDates = true;
            categoryAxis1.minPeriod = "ss";
            categoryAxis1.boldPeriodBeginning = true;
            categoryAxis1.dateFormats = [{ //展示的博客 时间区间
                period: ‘fff’,
                format: ‘JJ:NN:SS’
            }, {
                period: ‘ss’,
                format: ‘JJ:NN:SS’
            }, {
                period: ‘mm’,
                format: ‘JJ:NN’
            }, {
                period: ‘hh’,
                format: ‘JJ:NN’
            }, {
                period: ‘DD’,
                format: ‘DD’
            }, {
                period: ‘WW’,
                format: ‘DD’
            }, {
                period: ‘MM’,
                format: ‘MMM’
            }, {
                period: ‘YYYY’,
                format: ‘YYYY’
            }];
            var valueAxis1 = new AmCharts.ValueAxis();//样式
            valueAxis1.axisColor = "#0000C6";
            valueAxis1.gridColor = "#0000C6";
            valueAxis1.precision = 1;
            valueAxis1.autoGridCount = false;
            chart1.addValueAxis(valueAxis1);
            var chartCursor1 = new AmCharts.ChartCursor();
            chartCursor1.categoryBalloonDateFormat = "MM-DD JJ:NN:SS";  //鼠标放到折线图  时间展示格式
            chartCursor1.valueLineEnabled = true;
            chartCursor1.valueLineBalloonEnabled = true;
            chartCursor1.pan = false;
            chartCursor1.zoomable = true;
            chart1.addChartCursor(chartCursor1);
            var graphh1 = new AmCharts.AmGraph();
            graphh1.title = "历史值";
            graphh1.valueField = "dvalue";
            graphh1.balloonText = "<b><span style=’font-size:14px;’>历史值:[[dvalue]]</span></b>";  //获取的博客数据
            graphh1.lineColor = "#33CC00";
            chart1.addGraph(graphh1);

            var legend1 = new AmCharts.AmLegend();
            legend1.valueAlign = "left";
            legend1.useMarkerColorForLabels = true;
            legend1.useMarkerColorForValues = true;
            legend1.useGraphSettings = true;
            chart1.addLegend(legend1);
            chart1.write("avchischartdiv");   定义div  获取divid 生成折线图

        },
        failure: function () {
            Ext.Msg.alert(‘曲线’, ‘获取历史数据异常’);
        }
});

效果如下 amcharts 折线图

http://blog.csdn.net/si99999/article/details/76250734加勒比海盗5