热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringBoot自定义注解API数据加密和签名校验

这篇文章主要介绍了SpringBoot自定义注解API数据加密和签名校验,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

api数据数据签名(MD5,SHA1)

签名枚举类SginEnum.java

package com.jx.app.api.framework.annotation.enums;

/**  
* @ClassName: SginEnum  
* @Description: TODO(这是一个签名枚举类)  
* @author gangyu
* @date 2018年11月20日 下午4:30:44  
*/
public enum SginEnum {
 //0不需要签名,1使用MD5数据加密 2 使用SHA数据加密
 ANY(0), MD5(1), SHA1(2);
 private final int value;

 private SginEnum(int value) {
  this.value = value;
 }

 public int getValue() {
  return value;
 }
}

签名注解类SginAnot.java

/**    
* @Title: SginAnot.java  
* @Package com.jxkj.app.api.framework  
* @Description: TODO(用一句话描述该文件做什么)  
* @author gangyu
* @date 2018年11月20日 下午4:07:58  
* @version V1.0    
*/
package com.jx.app.api.framework.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.jx.app.api.framework.annotation.enums.SginEnum;

/**  
* @ClassName: SginAnot  
* @Description: TODO(签名验证注解)  
* @author gangyu
* @date 2018年11月20日 下午4:07:58  
*    
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SginAnot {
 SginEnum type() default SginEnum.ANY;//默认不需要签名
}

加密工具类MD5.java

package com.jx.common.entrypt;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jx.common.utils.BeanUtil;
import com.jx.common.utils.TestEntity;

/**
 * @ClassName: MD5
 * @Description: TODO(MD5加密工具)
 * @author gangyu
 * @date 2018年11月20日 下午2:12:14
 *
 */
public class MD5 {


 private static final Logger log = LoggerFactory.getLogger(MD5.class);

 public static String PRIVATE_KEY = "这是你的密钥";
 
    private static final String hexDigIts[] = {"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};

 public static String encrypt(String plainText) {
  try {
   return encrypt(plainText,true);
  } catch (UnsupportedEncodingException e) {
   e.printStackTrace();
   log.error("MD5加密异常:",e);
   return null;
  }
 }
 
 /**
  * @Title: encrypt
  * @Description: TODO(16位或32位密码)
  * @param @param
  *            plainText
  * @param @param
  *            flag true为32位,false为16位
  * @throws UnsupportedEncodingException
  */
 public static String encrypt(String plainText, boolean flag) throws UnsupportedEncodingException {
  try {
   if (StringUtils.isEmpty(plainText)) {
    return null;
   }
   MessageDigest md = MessageDigest.getInstance("MD5");
            String encrStr = byteArrayToHexString(md.digest(plainText.getBytes("UTF-8")));
   if (flag)
    return encrStr;
   else
    return encrStr.substring(8, 24);
  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
   return null;
  }

 }

 @SuppressWarnings("unchecked")
 public static String encrypt(Object obj){
  if(obj==null){
   return null;
  }
  Map map = new HashMap();
  if(obj instanceof Map){
   map=(Map) obj;
  }else{
   map = BeanUtil.transBean2Map(obj);
  }
  return encrypt(map,true);
 }
 
 /**
  * @Title: encrypt
  * @Description: TODO(16位或32位密码)
  * @param @param
  *            plainText
  * @param @param
  *            flag true为32位,false为16位
  * @throws UnsupportedEncodingException
  */
 public static String encrypt(Map map, boolean flag) {
  String param = null;
  map.remove("sign");
  map.remove("encrypt");
  String result = BeanUtil.mapOrderStr(map);
  if (StringUtils.isEmpty(result)) {
   return null;
  }
  param = encrypt(encrypt(result)+PRIVATE_KEY);
  if (flag) {
   return param;
  } else {
   param = param.substring(8, 24);
  }
  return param;
 }

 public static Map resultMap = new HashMap();
 @SuppressWarnings("unchecked")
 public static Map mapFn(Map map) {
  for (String key : map.keySet()) {
   if (map.get(key) != null && map.get(key) != "" && (!key.equals("BTYPE") && !key.equals("SIGN"))) {
    if (key.equals("INPUT")) {
     if (map.get(key) != null) {
      mapFn((Map) map.get(key));
     }
    } else {
     resultMap.put(key, map.get(key));
    }
   }
  }
  return resultMap;
 }
 
 @SuppressWarnings("unchecked")
 public static boolean check(Object obj){
  Map map=new HashMap();
  if(obj==null){
   return false;
  }
  if(obj instanceof Map){
   map=(Map) obj;
  }else{
   map = BeanUtil.transBean2Map(obj);
  }
  String sign=(String)map.get("sign");
  if(sign==null){
   return false;
  }
  String str=encrypt(obj);
  return sign.equals(str)?true:false;
 }

    public static String byteArrayToHexString(byte b[]){
        StringBuffer resultSb = new StringBuffer();
        for(int i = 0; i 

SHA加密工具类SHA1.java

package com.jx.common.entrypt;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jx.common.utils.BeanUtil;

/**  
* @ClassName: Sha1Util  
* @Description: TODO(SHA加密)  
* @author gangyu
* @date 2018年11月20日 下午2:08:36  
*    
*/
public class Sha1 {
 private static final Logger log = LoggerFactory.getLogger(Sha1.class);
 public static String encrypt(String str){
     if (null == str || 0 == str.length()){
         return null;
     }
     char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
             'a', 'b', 'c', 'd', 'e', 'f'};
     try {
         MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
         mdTemp.update(new String(str.getBytes("iso8859-1"), "utf-8").getBytes());
         byte[] md = mdTemp.digest();
         int j = md.length;
         char[] buf = new char[j * 2];
         int k = 0;
         for (int i = 0; i >> 4 & 0xf];
             buf[k++] = hexDigits[byte0 & 0xf];
         }
         return new String(buf);
     } catch (NoSuchAlgorithmException e) {
         e.printStackTrace();
   log.error("SHA1加密异常:",e);
     } catch (UnsupportedEncodingException e) {
         e.printStackTrace();
   log.error("SHA1加密异常:",e);
     }
  return str;
 }
 
 @SuppressWarnings("unchecked")
 public static String encrypt(Object obj) {
  if(obj==null){
   return null;
  }
  Map map = new HashMap();
  if(obj instanceof Map){
   map=(Map) obj;
  }else{
   map = BeanUtil.transBean2Map(obj);
  }
  map.remove("sign");
  map.remove("encrypt");
  String result = BeanUtil.mapOrderStr(map);
  if (StringUtils.isEmpty(result)) {
   return null;
  }
  return encrypt(result);
 }
 
 @SuppressWarnings("unchecked")
 public static boolean check(Object obj){
  Map map=new HashMap();
  if(obj==null){
   return false;
  }
  if(obj instanceof Map){
   map=(Map) obj;
  }else{
   map = BeanUtil.transBean2Map(obj);
  }
  String sign=(String)map.get("sign");
  if(sign==null){
   return false;
  }
  String str=encrypt(obj);
  return sign.equals(str)?true:false;
 
 }
}

返回数据对称加密DES.java

package com.jx.common.entrypt;

import java.security.Key;
import java.util.Map;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;

import com.google.gson.Gson;
import com.jx.common.utils.Base64;


/**
* @ClassName: Des  
* @Description: TODO(对称加密工具)  
* @author gangyu
* @date 2018年11月20日 下午1:18:49  
*/
public class DES {
 // 密钥
 private final static String secretKey = "123456789987654321";
 // 向量
 private final static String iv = "ggboy123";
 // 加解密统一使用的编码方式
 private final static String encoding = "utf-8";

 /**
 * @Title: encode
 * @Description: TODO(加密)
 * @param String
 * @author gangyu2
 * @date 2018年11月20日下午1:19:19
  */
 public static String encode(String plainText){
  Key deskey = null;
  DESedeKeySpec spec;
  try {
   spec = new DESedeKeySpec(secretKey.getBytes());
   SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
   deskey = keyfactory.generateSecret(spec);

   Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");
   IvParameterSpec ips = new IvParameterSpec(iv.getBytes());
   cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
   byte[] encryptData = cipher.doFinal(plainText.getBytes(encoding));
   return Base64.encode(encryptData);
  } catch (Exception e) {
   e.printStackTrace();
   return "";
  }
 }

 /**
 * @Title: decode
 * @Description: TODO(解密)
 * @param String
 * @author gangyu2
 * @date 2018年11月20日下午1:19:37
  */
 public static String decode(String encryptText){
  try{

   Key deskey = null;
   DESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes());
   SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
   deskey = keyfactory.generateSecret(spec);
   Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");
   IvParameterSpec ips = new IvParameterSpec(iv.getBytes());
   cipher.init(Cipher.DECRYPT_MODE, deskey, ips);

   byte[] decryptData = cipher.doFinal(Base64.decode(encryptText));

   return new String(decryptData, encoding);
  }catch(Exception e){
   e.printStackTrace();
   return "";
  }
 }
}

BeanUtil.java

package com.jx.common.utils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.lang3.StringUtils;

public class BeanUtil {

 // Map --> Bean 2: 利用org.apache.commons.beanutils 工具类实现 Map --> Bean
 public static void transMap2Bean2(Map map, Object obj) {
  if (map == null || obj == null) {
   return;
  }
  try {
   BeanUtils.populate(obj, map);
  } catch (Exception e) {
   System.out.println("transMap2Bean2 Error " + e);
  }
 }

 // Map --> Bean 1: 利用Introspector,PropertyDescriptor实现 Map --> Bean
 public static void transMap2Bean(Map map, Object obj) {
  try {
   BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
   PropertyDescriptor[] propertyDescriptors = beanInfo
     .getPropertyDescriptors();

   for (PropertyDescriptor property : propertyDescriptors) {
    String key = property.getName();

    if (map.containsKey(key)) {
     Object value = map.get(key);
     // 得到property对应的setter方法
     Method setter = property.getWriteMethod();
     setter.invoke(obj, value);
    }

   }

  } catch (Exception e) {
   System.out.println("transMap2Bean Error " + e);
  }

  return;

 }

 // Bean --> Map 1: 利用Introspector和PropertyDescriptor 将Bean --> Map
 public static Map transBean2Map(Object obj) {
  if (obj == null) {
   return null;
  }
  Map map = new HashMap();
  try {
   BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
   PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
   for (PropertyDescriptor property : propertyDescriptors) {
    String key = property.getName();

    // 过滤class属性
    if (!key.equals("class")) {
     // 得到property对应的getter方法
     Method getter = property.getReadMethod();
     Object value = getter.invoke(obj);
     if(null !=value && !"".equals(value))
      map.put(key, value);
    }

   }
  } catch (Exception e) {
   System.out.println("transBean2Map Error " + e);
  }
  return map;

 }
 
 public static String mapOrderStr(Map map) {
  List> list = new ArrayList>(map.entrySet());
  Collections.sort(list, new Comparator>() {
   public int compare(Entry o1, Entry o2) {
    return o1.getKey().compareTo(o2.getKey());
   }
  });

  StringBuilder sb = new StringBuilder();
  for (Map.Entry mapping : list) {
   sb.append(mapping.getKey() + "=" + mapping.getValue() + "&");
  }
  return sb.substring(0, sb.length() - 1);
 }
 
 

 /**
  * 
  * 将源的属性复制到目标属性上去
  * @param src
  * @param dest
  * @lastModified
  * @history
  */
 public static void copyProperties(Object dest,Object src) {
  if (src == null || dest == null) {
   return;
  }
  // 获取所有的get/set 方法对应的属性
  PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
  PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(src);

  for (int i = 0; i  T mapToEntity(Map map, Class entity) {
  T t = null;
  try {
   t = entity.newInstance();
   for(Field field : entity.getDeclaredFields()) {
    if (map.containsKey(field.getName())) {
     boolean flag = field.isAccessible();
              field.setAccessible(true);
              Object object = map.get(field.getName());
              if (object!= null && field.getType().isAssignableFrom(object.getClass())) {
                field.set(t, object);
     }
              field.setAccessible(flag);
    }
   }
   return t;
  } catch (InstantiationException e) {
   e.printStackTrace();
  } catch (IllegalAccessException e) {
   e.printStackTrace();
  }
  return t;

 } 

}

拦截器AppInterceptor.java

package com.jx.app.api.framework.interceptor;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import com.google.gson.Gson;
import com.jx.app.api.framework.annotation.LoginAnot;
import com.jx.app.api.framework.annotation.SginAnot;
import com.jx.app.api.framework.annotation.enums.Auth;
import com.jx.app.api.framework.annotation.enums.SginEnum;
import com.jx.common.entrypt.MD5;
import com.jx.common.entrypt.Sha1;
import com.jx.common.token.ServiceException;
import com.jx.common.token.TokenException;
import com.jx.common.token.TokenUtil;
import com.jx.common.utils.Constants;
import com.jx.common.utils.RequestUtil;
import com.jx.common.utils.Result;
import com.jx.common.utils.enums.CodeEnum;
import com.jx.core.api.model.BaseModel;

/**  
* @ClassName: AppInterceptor  
* @Description: TODO(拦截器)  
* @author gangyu
* @date 2018年11月20日 下午4:10:55  
*    
*/
public class AppInterceptor implements HandlerInterceptor{
    private final static Logger LOGGER = LoggerFactory.getLogger(AppInterceptor.class);
 
 private static final String CONTENT_TYPE="text/json;charset=UTF-8";
 
 @Override
 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
   throws Exception {
    if (handler.getClass().isAssignableFrom(HandlerMethod.class)) {
      //签名验证注解
          SginAnot signAnot = ((HandlerMethod) handler).getMethodAnnotation(SginAnot.class);
          
          //验签
          if(signAnot!=null && !signCheck(request,signAnot.type())){
              response.setContentType(CONTENT_TYPE);
                 response.getWriter().print(new Gson().toJson(new Result(CodeEnum.SIGN_FAIL)));
                 return false;
          }
    return true;
    }else{
    return true;
    }
 }

 private boolean signCheck(HttpServletRequest request,SginEnum enumm){
  Map map=RequestUtil.parseRequset(request);
  if(enumm==SginEnum.MD5){
   return MD5.check(map);
  }else if(enumm==SginEnum.SHA1){
   return Sha1.check(map);
  }
  return false;
 }
 }
 }
}

统一返回对象Result.java

package com.jx.common.utils;


import java.io.Serializable;

import com.google.gson.Gson;
import com.jx.common.entrypt.DES;
import com.jx.common.utils.enums.CodeEnum;

/**
 * 结果DTO
 * @lastModified
 * @history
 */

public class Result implements Serializable{
 private static final long serialVersiOnUID= 1L;

 /**
  * 结果详细
  */
 private String msg;

 /**
  * 需要传回页面的数据
  */
 private Object data;
 
 /**
  * 状态码
  */
 private String code;
 
 /**
  * 加密
  */
 private boolean encrypt;
 
 /**
  * 图标
  */
 private Integer icon;

 public boolean isEncrypt() {
  return encrypt;
 }

 public void setEncrypt(boolean encrypt) {
  this.encrypt = encrypt;
 }

 public String getMsg() {
  return msg;
 }

 public void setMsg(String msg) {
  this.msg = msg;
 }

 public Result() {

 }

 public Result(CodeEnum enums) {
  this.msg = enums.getMsg();
  this.encrypt = enums.getEncrypt();
  this.code = enums.getCode();
  this.icon = enums.getIcon();
 }

 public Result(CodeEnum enums,Object data) {
  this.msg = enums.getMsg();
  this.encrypt = enums.getEncrypt();
  this.code = enums.getCode();
  this.icon=enums.getIcon();
  if(enums.getEncrypt()){
   this.data=DES.encode(new Gson().toJson(data));
  }else{
   this.data=data;
  }
 }

 public Object getData() {
  return data;
 }

 public void setData(Object data) {
  this.data = data;
 }


 public String getCode() {
  return code;
 }

 public void setCode(String code) {
  this.code = code;
 }

 public Integer getIcon() {
  return icon;
 }

 public void setIcon(Integer icon) {
  this.icon = icon;
 }

 public static Result success(CodeEnum enums) {
  Result dto = new Result();
  dto.setMsg(enums.getMsg());
  dto.setEncrypt(enums.getEncrypt());
  dto.setCode(enums.getCode());
  dto.setIcon(enums.getIcon());
  return dto;
 }
 
 public static Result success(CodeEnum enums,Object data) {
  Result dto = new Result();
  dto.setData(data);
  dto.setEncrypt(enums.getEncrypt());
  dto.setCode(enums.getCode());
  dto.setIcon(enums.getIcon());
  if(enums.getEncrypt()){
   dto.setData(DES.encode(new Gson().toJson(data)));
  }else{
   dto.setData(data);
  }
  return dto;
 }
 
 public static Result fail(String msg) {
  Result dto = new Result();
  dto.setMsg(msg);
  dto.setEncrypt(false);
  dto.setCode("1");
  dto.setIcon(SysCode.ICON.ICON_FAIL);
  return dto;
 }
}

状态码枚举类CodeEnum.java

package com.jx.common.utils.enums;
/**  
* @ClassName: ExceptionEnum  
* @Description: TODO(系统编码)  
* @author gangyu
* @date 2018年11月21日 下午5:22:32  
*/
public enum CodeEnum {
 //系统编码
    SYS_EXCEPTION("999",false,"系统异常",'fail'),
    SUCCESS("0",false,"成功",'success'),
    ENCRYPT("0",true,"成功",'success'),
    FAIL("1",false,"失败",'fail'),
    SIGN_FAIL("1",false,"签名不正确",'fail'),
    DATA_EMPTY("0",false,"暂无数据",'success'),
    ;

    private String code;
    
    private String msg;
    
    private Boolean encrypt;
    
    private Integer icon;

    CodeEnum(String code,Boolean encrypt, String msg,Integer icon) {
        this.code = code;
        this.encrypt = encrypt;
        this.msg = msg;
        this.icon = icon;
    }

    public Integer getIcon() {
  return icon;
 }

 public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

 public Boolean getEncrypt() {
  return encrypt;
 }    
}

Controller层使用签名注解

 @RequestMapping(value="encryptEntity",produces = "application/json;charset=UTF-8",method=RequestMethod.POST)
    @SginAnot(type = SginEnum.MD5)
    public  Object encryptEntity(TestEntity test){
        return businessService.encryptEntity(test);
    }
  • 验签加密排序根据ASII表进行排序在BeanUtil.java类里已经实现
  • url?a=1&c=2&b=3。。。->排序后 a=1&b=3&c=2 然后进行数据加密 俩边排序方式要一致当然为了安全可以排完序加入自己的密钥在进行一次加密
  • Result.java提供了返回数据加密方法CodeEnum.ENCRYPT这里使用的是DES对称加密

到此这篇关于SpringBoot自定义注解API数据加密和签名校验的文章就介绍到这了,更多相关SpringBoot 数据加密和签名校验内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • Android日历提醒软件开源项目分享及使用教程
    本文介绍了一款名为Android日历提醒软件的开源项目,作者分享了该项目的代码和使用教程,并提供了GitHub项目地址。文章详细介绍了该软件的主界面风格、日程信息的分类查看功能,以及添加日程提醒和查看详情的界面。同时,作者还提醒了读者在使用过程中可能遇到的Android6.0权限问题,并提供了解决方法。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • 本文介绍了一些Java开发项目管理工具及其配置教程,包括团队协同工具worktil,版本管理工具GitLab,自动化构建工具Jenkins,项目管理工具Maven和Maven私服Nexus,以及Mybatis的安装和代码自动生成工具。提供了相关链接供读者参考。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • Java如何导入和导出Excel文件的方法和步骤详解
    本文详细介绍了在SpringBoot中使用Java导入和导出Excel文件的方法和步骤,包括添加操作Excel的依赖、自定义注解等。文章还提供了示例代码,并将代码上传至GitHub供访问。 ... [详细]
  • 本文介绍了JavaScript进化到TypeScript的历史和背景,解释了TypeScript相对于JavaScript的优势和特点。作者分享了自己对TypeScript的观察和认识,并提到了在项目开发中使用TypeScript的好处。最后,作者表示对TypeScript进行尝试和探索的态度。 ... [详细]
  • 在package.json中有如下两个对象:husky:{hooks:{pre-commit:lint-staged}},lint-staged:{src** ... [详细]
  • 本文总结了初学者在使用dubbo设计架构过程中遇到的问题,并提供了相应的解决方法。问题包括传输字节流限制、分布式事务、序列化、多点部署、zk端口冲突、服务失败请求3次机制以及启动时检查。通过解决这些问题,初学者能够更好地理解和应用dubbo设计架构。 ... [详细]
  • Tomcat安装与配置教程及常见问题解决方法
    本文介绍了Tomcat的安装与配置教程,包括jdk版本的选择、域名解析、war文件的部署和访问、常见问题的解决方法等。其中涉及到的问题包括403问题、数据库连接问题、1130错误、2003错误、Java Runtime版本不兼容问题以及502错误等。最后还提到了项目的前后端连接代码的配置。通过本文的指导,读者可以顺利完成Tomcat的安装与配置,并解决常见的问题。 ... [详细]
author-avatar
流浪1种无奈
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有