Java开发工程师必会技术自检清单


0 前言

俗话说:“吾日三省吾身”,经常性地自检有助于查漏补缺,逐步提升技术水平。Java开发所要面对的技术多如牛毛,没有一份明确的清单很难去排查。为解决以上难题,我根据常用和实用两点原则,总结如下技术清单。
愿大家技术进步,与君共勉。


1 Java web方面

1.1 全局异常处理

主要注意的点是http响应码,这涉及到“锅由谁来背”。众所周知,500响应码是系统内部错误。很不幸的是,全局异常处理默认的响应码就是500。当然,锅能不背就不背。大胆的将ResponseStatus设成HttpStatus.OK之后,你会发现大部分请求都回归了200响应码。
当然,错误信息还是要传递出去的。通过在返回JSON添加returnCode字段,就可以将异常信息与正常信息区分出来。

核心代码如下所示:

/**
 * 跟定义顺序无关,只是优先处理具体异常
 * @author yiqiang
 * @date 2020/8/7 10:31
 */
@ControllerAdvice
@Slf4j
@ResponseBody
public class GlobalExceptionHandler {

    private static final String COMMON_EXCEPTION="COMMON EXCEPTION: ";

    private static final String SERIOUS_EXCEPTION="SERIOUS_EXCEPTION: ";

    private static final String UNKNOWN_EXCEPTION="UNKNOWN_EXCEPTION: ";

    @ExceptionHandler(value = {CommonException.class})
    @ResponseStatus(value = HttpStatus.OK)
    public String commonHandler(CommonException e) throws JsonProcessingException {
        log.error(e.getMessage());
        e.printStackTrace();
        return ReturnDTO.failToJson(COMMON_EXCEPTION + e.getMessage(),null);
    }

    @ExceptionHandler(value = {SeriousException.class})
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public String seriousHandler(SeriousException e) throws JsonProcessingException {
        log.error(e.getMessage());
        e.printStackTrace();
        return ReturnDTO.failToJson(SERIOUS_EXCEPTION + e.getMessage(),null);
    }

    @ExceptionHandler(value = {Exception.class})
    @ResponseStatus(value = HttpStatus.OK)
    public String unknownHandler(Exception e) throws JsonProcessingException {
        log.error(e.getMessage());
        e.printStackTrace();
        return ReturnDTO.failToJson(UNKNOWN_EXCEPTION + "PLEASE CONNECT TO MANAGER",null);
    }

}

个人强烈建议,不要将异常堆栈信息直接返回给前端,而应该返回自定义的“帮助信息”。毕竟,返回堆栈信息一方面不安全;另一方面,返回的信息对不是程序员的客户没有任何帮助。
具体做法也很简单:实现建立异常枚举类和自定义异常,直接抛出自定义异常即可。

1.2 拦截器写法

拦截器对于绝大多数Java工程师而言,也是必备技能。废话不多说,步骤如下。

  1. 继承HandlerInterceptor,并作为component传递给Spring容器
@Component
@Slf4j
public class PtzRoleInterceptor implements HandlerInterceptor{


    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        log.info("PtzRoleInterceptor 成功拦截 ==> [{}]",httpServletRequest.getRequestURL());
        String roleIds = httpServletRequest.getHeader("roleIds");
        log.info("roleIds {}",roleIds);
        if(roleIds==null){
            log.info("roleIds为空");
        }
        boolean role=true;
        if(!StringUtils.isEmpty(roleIds)){
            for (String roleId : roleIds.split(",")) {
                if (ConstantUtil.PTZ_CONTROLLER_ROLE_ID.equals(roleId)) {
                    role = false;
                }
            }
        }

        if(role){
            //信息返回
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("text/html;charset=utf-8");
            try(PrintWriter writer = httpServletResponse.getWriter()){
                JSONObject jsonObject=new JSONObject();
                jsonObject.put("returnCode",1);
                jsonObject.put("returnMsg","权限不足.如有需要,请联系配置管理员");
                writer.print(JSONObject.toJSONString(jsonObject,true));
            }catch (Exception e){
                e.printStackTrace();
                log.error("出现异常"+e.getMessage());
            }
            log.info("PtzRoleInterceptor 校验失败 ==> [{}],当前用户角色ID为{}",httpServletRequest.getRequestURL(),roleIds);
            return false;
        }else {
            log.info("PtzRoleInterceptor 校验成功 ==> [{}],当前用户角色ID为{}",httpServletRequest.getRequestURL(),roleIds);
            return true;
        }

    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}
  1. 对拦截器进行配置
/**
 * @author yiqiang
 * @date 2020/6/19 15:19
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Resource
    private PtzRoleInterceptor ptzRoleInterceptor;

    @Resource
    private PtzControlInterceptor ptzControlInterceptor;


    @Override
    public void addInterceptors(InterceptorRegistry interceptorRegistry) {
        interceptorRegistry.addInterceptor(ptzRoleInterceptor).
                addPathPatterns("/realTimeStream/lockChannel",
                        "/realTimeStream/ptzCtrl",
                        "/realTimeStream/showLockChannel",
                        "/realTimeStream/unlockChannel",
                        "/realTimeStream/seizeChannel");
        interceptorRegistry.addInterceptor(ptzControlInterceptor).
                addPathPatterns("/realTimeStream/ptzCtrl");
    }

}

1.3 自定义注解和切面写法

自定义注解类

import java.lang.annotation.*;

@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Timeout {
    long value() default 1000;
}

切面类的编写

/**
 * @author yiqiang
 * @date 2020/8/12 13:38
 */
@Aspect
@Slf4j
@Component
public class TimeoutAspect {

    @Pointcut(value = "@annotation(com.gosun.pcms.aop.Timeout)")
    public void pointCut() {
    }
    
    @Around(value = "pointCut()")
    public Object timeOut(ProceedingJoinPoint joinPoint) throws Exception {
        log.info("正在进入切面");
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        Timeout timeOut = method.getDeclaredAnnotation(Timeout.class);
        int i = 0;
        ExecutorService executor = Executors.newCachedThreadPool();
        Future future = executor.submit(() -> {
            log.info("正在执行");
            try {
                return joinPoint.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
                return ReturnDTO.fail("操作失败");
            }
        });
        long t = System.currentTimeMillis();
        while (true) {
            Thread.sleep(1000);
            log.info("第{}次执行", i++);
            if (System.currentTimeMillis() - t >= timeOut.value()) {
                return ReturnDTO.fail("超时,TimeOut:"+timeOut.value());
            }
            if (future.isDone()) {
                return future.get();
            }
        }
    }

}

1.4 线程池的使用

声明executor,然后使用executor的submit或者execute方法创建线程。前者针对callable接口,后者针对runable接口。

    ExecutorService executor = Executors.newCachedThreadPool();
    Future future = executor.submit(() -> {
        	//do something
    });
    if(future.isDone()){
    	log.info(future.get())
    }

1.5 跨域过滤器

偶尔会遇到跨域问题,只要在启动类添加如下配置即可

   private CorsConfiguration buildConfig() {
      CorsConfiguration corsConfiguration = new CorsConfiguration();
      corsConfiguration.addAllowedOrigin("*");
      corsConfiguration.addAllowedHeader("*");
      corsConfiguration.addAllowedMethod("*");
      return corsConfiguration;
   }

   @Bean
   public CorsFilter corsFilter() {
      UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
      source.registerCorsConfiguration("/**", buildConfig()); 
      return new CorsFilter(source);
    }

1.6 文件上传与下载

1.7 WebSocket基本使用

1.8 图片转Base64编码

1.9 JSON转化

1.10 XML转化

1.11 自定义Starter

2 消息中间件

2.1 Rabbit MQ

2.1.1 AMQP协议

2.1.2 消息100%投递

2.1.3 死信队列

2.2 Kafka

2.2.1 Kafka与Spring整合

2.2.2 Kafka配置详解

3 缓存中间件

3.1 本地缓存EhCache

3.2 分布式缓存Redis

3.3 缓存失效及解决方案

4 ES基础知识

4.1 ELK系统搭建

4.2 ES基本增删改查

5 数据库基础

5.1 主从复制

5.2 分库分表

5.3 SQL调优

6 JVM基础

7 前端基础

7.1 原生JS发送ajax

<script>
    var xmlHttp;
    if(window.XMLHttpRequest){
        xmlHttp = new XMLHttpRequest();
    }else{
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    request.open("GET", "http://localhost:8080/test",true);
    request.send(null);
    request.onreadystatechange = function() {
        if (request.readyState==4) {
            if (request.status==200) {
                var data = JSON.parse(request.responseText);
                if (data.success) {
                    document.getElementById("XXX").innerHTML = data.msg;
                } else {
                    document.getElementById("XXX").innerHTML = "出现错误:" + data.msg;
                }
            } else {
                alert("发生错误:" + request.status);
            }
        }
    }
</script>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值