springboot中的拦截器interceptor和过滤器filter,多次获取request参数

大家好,我是烤鸭:
    这是一篇关于springboot的拦截器(interceptor)和过滤器(Filter)。

    先说一下过滤器和拦截器。


区别:
1. servlet请求,顺序:Filter ——> interceptor。
2. Filter的作用是对所有进行过滤,包括接口或者静态资源,interceptor 仅拦截 请求。
3. Filter对请求或者资源进行过滤,筛选合适的请求或者资源。interceptor,仅对不符合的请求拦截。
4. Filter基于回调函数,我们需要实现的filter接口中doFilter方法就是回调函数,而interceptor则基于 
    java本身的反射机制,这是两者最本质的区别。
5. Filter是依赖于servlet容器的,即只能在servlet容器中执行,很显然没有servlet容器就无法来回调
    doFilter方法。而interceptor与servlet容器无关。


后面代码较多,不太适合看。

提前总结一下,我这里的过滤器和拦截器的使用:

filter: 目的就是可以以流的方式多次获取请求参数。
Interceptor对回调接口进行统一的验证签名。
回调接口都需要验证签名,而且签名规则一样,所以想拿到拦截器处理。

如果签名或者ip地址不符合条件,直接就返回了。而具体的接口只要专注业务处理,不需要验证签名了。

下面贴一下在springboot中的使用:

1. filter:

InterfaceFilter.java

package com.test.test.filter;import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebFilter(urlPatterns = "/*", filterName = "InterfaceFilter")
public class InterfaceFilter implements Filter{private static Logger log = LoggerFactory.getLogger(InterfaceFilter.class);@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse res = (HttpServletResponse) response;try {if ("POST".equals(req.getMethod().toUpperCase())) {// 获取请求参数byte[] bytes = IOUtils.toByteArray(request.getInputStream());String params = new String(bytes, req.getCharacterEncoding());ThreadCache.setPostRequestParams(params);log.info("filer-post请求参数:[params={}]", params);} else {log.info("非post请求");}chain.doFilter(request, response);} catch (Exception e) {log.error(e.getMessage(), e);}}@Overridepublic void destroy() {}
}

ThreadCache.java:

package com.test.test.filter;
public class ThreadCache {// ThreadLocal里只存储了简单的String对象,也可以自己定义对象,存储更加复杂的参数private static ThreadLocal<String> threadLocal = new ThreadLocal<String>();public static String getPostRequestParams(){return threadLocal.get();}public static void setPostRequestParams(String postRequestParams){threadLocal.set(postRequestParams);}public static void removePostRequestParams(){threadLocal.remove();}
}

说一下WebFilter注解。

urlPatterns指的是过滤哪个路径。跟在xml中配置是一样的作用。

简单说一下,我这个过滤器的作用。目的就是可以以流的方式多次获取请求参数。
正常requst.getInputStream只能获取一次。但是我在过滤器中将他的参数放到threadlocal中,
这样当前请求中就可以获取到请求参数了。
另外说一下:
有两种方式实现多次获取request参数。
1. 创建threadlocal类,将request或者request的参数放进去。
2. 创建wrapper类,类似装饰者模式,对request对象进行处理。getInputStream之后将流重新set进去。


推荐一篇多次获取request参数的博客:

https://www.cnblogs.com/endstart/p/6196807.html

2. Interceptor:

PlatformInterceptor.java:

package com.test.test.interceptor;import java.util.Map;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import com.alibaba.fastjson.JSONObject;
import com.test.test.config.ConfigProperties;
import com.test.test.constants.IMsgEnum;
import com.test.test.filter.ThreadCache;
import com.test.test.resp.BaseResp;
import com.test.test.security.SignCheck;
import com.test.test.utils.DESTools;
import com.test.test.utils.JsonUtil;
import com.test.test.utils.LogUtils;
import com.test.test.utils.NetworkUtil;
import com.test.test.utils.ReflectUtil;/*** ClassName: PlatformInterceptor date: 2015年12月30日 下午2:13:24 Description: 拦截器* * @author xiaozhan* @version* @since JDK 1.8*/
@Component
public class PlatformInterceptor implements HandlerInterceptor {private static final Log logger = LogFactory.getLog(PlatformInterceptor.class);@Autowiredprivate SignCheck signCheck;@Autowiredprivate ConfigProperties configProperties;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {logger.info(LogUtils.getRequestLog(request));// 获取自定义注解String allowOrigin = null;String servletPath = request.getServletPath();boolean isDeprecated = false;BaseResp baseResp = new BaseResp();ServletOutputStream out = response.getOutputStream();if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;Deprecated deprecated = handlerMethod.getMethodAnnotation(Deprecated.class);if (deprecated != null) {isDeprecated = true;}}String method = request.getMethod();if (!method.equals(RequestMethod.POST.name())) {baseResp.getMsg().setRstcode(IMsgEnum.PARAM_REQUEST_METHOD_FALSE.getMsgCode());baseResp.getMsg().setRsttext(IMsgEnum.PARAM_REQUEST_METHOD_FALSE.getMsgText());logger.info("----- " + IMsgEnum.PARAM_REQUEST_METHOD_FALSE.getMsgText() + " -----");out.write(JSONObject.toJSONString(baseResp).getBytes("UTF-8"));return false;}String clientIp = NetworkUtil.getIpAddress(request);logger.info("------ client Ip is ---》" + clientIp);// 判断是否是ip白名单if (!signCheck.checkIpAddress(clientIp)) {baseResp.getMsg().setRstcode(IMsgEnum.PARAM_IP_ADDRESS_FALSE.getMsgCode());baseResp.getMsg().setRsttext(IMsgEnum.PARAM_IP_ADDRESS_FALSE.getMsgText());logger.info("----- " + IMsgEnum.PARAM_IP_ADDRESS_FALSE.getMsgText() + " -----");out.write(JSONObject.toJSONString(baseResp).getBytes("UTF-8"));return false;}// 验证签名String params = ThreadCache.getPostRequestParams();logger.info("interceptor-post请求参数:[params={}]" + params);Map<String, Object> map = ReflectUtil.getDecodeParamMap(params);String sign = (String) map.get("sign");if (map.containsKey("sign")) {map.remove("sign");}// 签名校验if (!SignCheck.checkSign(map, sign, configProperties.getPrivateKey())) {baseResp.getMsg().setRstcode(IMsgEnum.PARAM_SIGN_FALSE.getMsgCode());baseResp.getMsg().setRsttext(IMsgEnum.PARAM_SIGN_FALSE.getMsgText());logger.info("----- " + IMsgEnum.PARAM_SIGN_FALSE.getMsgText() + " -----");out.write(JSONObject.toJSONString(baseResp).getBytes("UTF-8"));return false;}try {if (isDeprecated) {logger.error(LogUtils.getCommLog(String.format("该接口已停止使用,%s", servletPath)));}} catch (Exception e) {baseResp.getMsg().setRstcode(IMsgEnum.PARAMETER_INVALID.getMsgCode());baseResp.getMsg().setRsttext(IMsgEnum.PARAMETER_INVALID.getMsgText());logger.info("----- " + IMsgEnum.PARAMETER_INVALID.getMsgText() + " -----");out.write(JSONObject.toJSONString(baseResp).getBytes("UTF-8"));return false;}return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {}}
可以针对某些具体的请求进行拦截。我这里没做限制,所有的请求都走。

如果想拦截 特定的请求,判断一下request.getContextPath()是否包含某个路径。(后续更新)

我这里用到拦截器的作用是对回调接口进行统一的验证签名。
回调接口都需要验证签名,而且签名规则一样,所以想拿到拦截器处理。
如果签名或者ip地址不符合条件,直接就返回了。而具体的接口只要专注业务处理,不需要验证签名了。

分享一下用的工具类:ip和签名校验:


signCheck.java:

package com.test.test.security;import java.util.Arrays;
import java.util.List;
import java.util.Map;import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;import com.alibaba.fastjson.JSONObject;
import com.test.test.config.ConfigProperties;
import com.test.test.interceptor.PlatformInterceptor;
import com.test.test.utils.Signature;
import org.springframework.stereotype.Service;/** 
* @author gmwang E-mail: 
* @version 创建时间:2018年3月1日 上午10:35:47 
* 类说明 :校验签名和ip
*/
@Service(value="signCheck")
public class SignCheck{private static final Log logger = LogFactory.getLog(PlatformInterceptor.class);@Autowiredprivate ConfigProperties configProperties;@Beanpublic SignCheck getSignCheck(){return new SignCheck();}/*** 校验签名* @Description:* @author:* @throws IllegalAccessException * @time:2018年3月1日 上午10:38:09*/public static Boolean checkSign(Map params, String sign,String privateKey) throws IllegalAccessException {if(StringUtils.isBlank(sign)) {logger.info("*********************sign is null*********************");return false;}else {String signAfter = Signature.getSign(params,privateKey);System.out.println("sign:"+sign);System.out.println("signAfter:"+signAfter);if(!sign.equals(signAfter)) {logger.info("*********************sign is not equal signAfter*********************");return false;}}return true;}/*** 校验ip* @Description:* @author:* @throws IllegalAccessException * @time:2018年3月1日 上午10:38:09*/public Boolean checkIpAddress(String ip) throws IllegalAccessException {String ipWhite = configProperties.getRequestUrl();System.out.println(ipWhite);String[] ipWhiteArray = ipWhite.split(",");List<String> ipWhiteList = Arrays.asList(ipWhiteArray);if(!ipWhiteList.contains(ip)) {logger.info("*********************ip is not in ipWhiteList*********************");return false;}return true;}
}
获取ip地址工具类:

NetworkUtil.java:

package com.test.test.utils;import java.io.IOException;import javax.servlet.http.HttpServletRequest;import org.apache.log4j.Logger;/** * 常用获取客户端信息的工具 *  */  
public final class NetworkUtil {  /** * Logger for this class */  private static Logger logger = Logger.getLogger(NetworkUtil.class);  /** * 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址; *  * @param request * @return * @throws IOException */  public final static String getIpAddress(HttpServletRequest request) throws IOException {  // 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址  String ip = request.getHeader("X-Forwarded-For");  if (logger.isInfoEnabled()) {  logger.info("getIpAddress(HttpServletRequest) - X-Forwarded-For - String ip=" + ip);  }  if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  ip = request.getHeader("Proxy-Client-IP");  if (logger.isInfoEnabled()) {  logger.info("getIpAddress(HttpServletRequest) - Proxy-Client-IP - String ip=" + ip);  }  }  if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  ip = request.getHeader("WL-Proxy-Client-IP");  if (logger.isInfoEnabled()) {  logger.info("getIpAddress(HttpServletRequest) - WL-Proxy-Client-IP - String ip=" + ip);  }  }  if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  ip = request.getHeader("HTTP_CLIENT_IP");  if (logger.isInfoEnabled()) {  logger.info("getIpAddress(HttpServletRequest) - HTTP_CLIENT_IP - String ip=" + ip);  }  }  if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  ip = request.getHeader("HTTP_X_FORWARDED_FOR");  if (logger.isInfoEnabled()) {  logger.info("getIpAddress(HttpServletRequest) - HTTP_X_FORWARDED_FOR - String ip=" + ip);  }  }  if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  ip = request.getRemoteAddr();  if (logger.isInfoEnabled()) {  logger.info("getIpAddress(HttpServletRequest) - getRemoteAddr - String ip=" + ip);  }  }  } else if (ip.length() > 15) {  String[] ips = ip.split(",");  for (int index = 0; index < ips.length; index++) {  String strIp = (String) ips[index];  if (!("unknown".equalsIgnoreCase(strIp))) {  ip = strIp;  break;  }  }  }  return ip;  }  
}  
加密解密工具类:

Signature.java:

package com.test.test.utils;import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;import com.alibaba.fastjson.JSONObject;/*** User: * Date: 2015/8/26* Time: 15:23*/
public class Signature {/*** 签名算法* @param o 要参与签名的数据对象* @return 签名* @throws IllegalAccessException*规则:签名,将筛选的参数按照第一个字符的键值ASCII码递增排序(字母升序排序),如果遇到相同字符则按照第二个字符的键值ASCII码递增排序,以此类推,形成key=value& * skey的字符串MD5加密; (必填)*/public static String getSign(Object o) throws IllegalAccessException {ArrayList<String> list = new ArrayList<String>();Class cls = o.getClass();Field[] fields = cls.getDeclaredFields();for (Field f : fields) {f.setAccessible(true);if (f.get(o) != null && f.get(o) != "") {list.add(f.getName() + "=" + f.get(o) + "&");}}int size = list.size();String [] arrayToSort = list.toArray(new String[size]);Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);StringBuilder sb = new StringBuilder();for(int i = 0; i < size; i ++) {sb.append(arrayToSort[i]);}String result = sb.toString();System.out.println(result);result = MD5Util.MD5Encode(result).toUpperCase();System.out.println(result);return result;}public static String getSign(Map<String,Object> map,String privateKey){ArrayList<String> list = new ArrayList<String>();for(Map.Entry<String,Object> entry:map.entrySet()){if(entry.getValue()!=""){list.add(entry.getKey() + "=" + entry.getValue() + "&");}}int size = list.size();String [] arrayToSort = list.toArray(new String[size]);Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);StringBuilder sb = new StringBuilder();for(int i = 0; i < size; i ++) {sb.append(arrayToSort[i]);}sb.append(privateKey);String result = sb.toString();System.out.println(result);result = MD5Util.MD5Encode(result).toUpperCase();return result;}public static void main(String[] args) {/** */Map<String,Object> map=new HashMap();map.put("uuid","PC0000000056");String result= getSign(map,"aaaaa!aaa");System.out.println(result);map.put("sign", result);//signDESTools desTools = new DESTools();String s = JSONObject.toJSONString(map);System.out.println(s);String param= desTools.getEncString(s);String str= HttpUtil.doPost("http://localhost:8111/test/test", param);System.out.println(str);}
}

DESTools.java:

package com.test.test.utils;
import java.security.Key;import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import org.apache.commons.codec.binary.Base64;public class DESTools {public static  DESTools instance;public static DESTools   getInstace(){if(instance == null){instance = new DESTools();}return instance;}Key key;/*** 密钥*/private static byte[] BOSS_SECRET_KEY = { 0x0b, 0x13, (byte) 0xe7,(byte) 0xb2, 0x51, 0x0d, 0x75, (byte) 0xc2, 0x4e, (byte) 0xdd,(byte) 0x4b, (byte) 0x51, 0x24, 0x36, (byte) 0xa8, (byte) 0x28,0x0b, 0x13, (byte) 0xe2, (byte) 0xb2, 0x31, 0x0d, 0x75, (byte) 0xc1 };public DESTools() {setKey(BOSS_SECRET_KEY);}/*** 根据参数生成KEY*/public void setKey(byte[] strKey) {try {DESKeySpec dks = new DESKeySpec(BOSS_SECRET_KEY);SecretKeyFactory keyFactory;keyFactory = SecretKeyFactory.getInstance("DES");this.key = keyFactory.generateSecret(dks);} catch (Exception e) {throw new RuntimeException("Error initializing DESTOOLS class. Cause: " + e);}}/*** 加密String明文输入,String密文输出*/public String getEncString(String strMing) {byte[] byteMi = null;byte[] byteMing = null;String strMi = "";Base64 base64en = new Base64();try {byteMing = strMing.getBytes("UTF8");byteMi = this.getEncCode(byteMing);strMi = base64en.encodeAsString(byteMi);} catch (Exception e) {throw new RuntimeException("Error initializing DESTOOLS class. Cause: " + e);} finally {base64en = null;byteMing = null;byteMi = null;}return strMi;}/*** 解密 以String密文输入,String明文输出* @param strMi* @return*/public String getDesString(String strMi) {Base64 base64De = new Base64();byte[] byteMing = null;byte[] byteMi = null;String strMing = "";try {byteMi = base64De.decode(strMi);byteMing = this.getDesCode(byteMi);strMing = new String(byteMing, "UTF8");} catch (Exception e) {throw new RuntimeException("Error initializing DESTOOLS class. Cause: " + e);} finally {base64De = null;byteMing = null;byteMi = null;}return strMing;}/*** 加密以byte[]明文输入,byte[]密文输出* @param byteS* @return*/private byte[] getEncCode(byte[] byteS) {byte[] byteFina = null;Cipher cipher;try {cipher = Cipher.getInstance("DES");cipher.init(Cipher.ENCRYPT_MODE, key);byteFina = cipher.doFinal(byteS);} catch (Exception e) {throw new RuntimeException("Error initializing DESTOOLS class. Cause: " + e);} finally {cipher = null;}return byteFina;}/*** 解密以byte[]密文输入,以byte[]明文输出* @param byteD* @return*/private byte[] getDesCode(byte[] byteD) {Cipher cipher;byte[] byteFina = null;try {cipher = Cipher.getInstance("DES");cipher.init(Cipher.DECRYPT_MODE, key);byteFina = cipher.doFinal(byteD);} catch (Exception e) {throw new RuntimeException("Error initializing DESTOOLS class. Cause: " + e);} finally {cipher = null;}return byteFina;}}

获取yml文件的值:
ConfigProperties.java:

package com.test.test.config;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;@Configuration
@Component
public class ConfigProperties {@Value("${test.test.privateKey}")private String privateKey;@Value("${test.test.requestUrl}")private String requestUrl;public String getPrivateKey() {return privateKey;}public void setPrivateKey(String privateKey) {this.privateKey = privateKey;}public String getRequestUrl() {return requestUrl;}public void setRequestUrl(String requestUrl) {this.requestUrl = requestUrl;}}

yml文件如图:



2018-07-08 更新:

springboot 2.x 过滤器和拦截器 放行某个路径(静态资源):

package xxx.xxxx.config;import java.util.ArrayList;
import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import xxx.xxxx.interceptor.PlatformInterceptor;@EnableWebMvc
@Configuration
@Component
public class WebMvcConfig implements WebMvcConfigurer {@AutowiredPlatformInterceptor passportInterceptor;/*** 处理拦截器 拦截路径(暂时无效)*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 多个拦截器组成一个拦截器链registry.addInterceptor(passportInterceptor).addPathPatterns("/**").excludePathPatterns("notify","/static/**");WebMvcConfigurer.super.addInterceptors(registry);}/*** 处理过滤器  静态资源放行*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");WebMvcConfigurer.super.addResourceHandlers(registry);}/*** 利用fastjson替换掉jackson,且解决中文乱码问题* @param converters*/@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();FastJsonConfig fastJsonConfig = new FastJsonConfig();fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);//处理中文乱码问题List<MediaType> fastMediaTypes = new ArrayList<>();fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);fastConverter.setSupportedMediaTypes(fastMediaTypes);fastConverter.setFastJsonConfig(fastJsonConfig);converters.add(fastConverter);WebMvcConfigurer.super.configureMessageConverters(converters);}}



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/412998.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

利用cookies跳过登陆验证码

前言在爬取某些网页时&#xff0c;登陆界面时经常遇到的一个坎&#xff0c;而现在大多数的网站在登陆时都会要求用户填写验证码。当然&#xff0c;我们可以设计一套机器学习的算法去破解验证码&#xff0c;然而&#xff0c;验证码的形式多种多样&#xff0c;稍微变一下&#xf…

[Swift]八大排序算法(八):基数排序

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号&#xff1a;山青咏芝&#xff08;shanqingyongzhi&#xff09;➤博客园地址&#xff1a;山青咏芝&#xff08;https://www.cnblogs.com/strengthen/ &#xff09;➤GitHub地址&…

推一波JAVA学习公众号

大家好&#xff0c;我是烤鸭&#xff0c;今天不水了。分享一波java学习公众号。从基础到架构都有&#xff0c;另外说一句&#xff0c;注意身体吧。另外说一句&#xff0c;本文不定时更新。1. JAVA思维导图2. 程序员小灰可爱的小仓鼠3. 码农每日一题4. JAVA后端技…

二叉树的三种遍历(递归与非递归) + 层次遍历

<转载于 >>> > 二叉树是一种非常重要的数据结构&#xff0c;很多其他数据机构都是基于二叉树的基础演变过来的。二叉树有前、中、后三种遍历方式&#xff0c;因为树的本身就是用递归定义的&#xff0c;因此采用递归的方法实现三种遍历&#xff0c;不仅代码简洁…

springboot使用mongodb

大家好&#xff0c;我是烤鸭&#xff1a;这是一篇关于springboot项目中使用mongodb。 环境&#xff1a;jdk 1.8springboot 1.5.6.RELEASEmaven 3.5 1. mongodb在springboot中的配置springboot集成这个三方插件就是简单&#xff0c;只需要引入依赖&#xff0c;在properties或者…

eclipse搜索框太小

解决方式&#xff1a; Window>Preferences>DevStyle>Inline Search 把 use the inline search 取消勾选

fileinput 加 ftp 加 nginx 加 SpringBoot上传文件

亲测可用 准备linux服务器 https://www.cnblogs.com/shuaifing/p/8268949.html 搭建ftp https://www.cnblogs.com/shuaifing/p/8260532.html Springboot整合fileinput 上传文件https://www.cnblogs.com/shuaifing/p/8274906.html 页面 引入 jquery boostrap fileinput.min.js…

Centos7安装Hadoop教程

一&#xff1a;安装SSH 1&#xff0c;执行下面的命令安装ssh yum install openssh-clients yum install openssh-server 2&#xff0c;执行如下命令测试一下 SSH 是否可用&#xff08;SSH首次登陆提示 yes/no 信息&#xff0c;输入 yes 即可&#xff0c;然后按照提示输入 root…

elasticsearch 6.x (一) 部署 windows入门 spingboot连接

大家好&#xff0c;我是烤鸭&#xff1a;今天分享的是 elasticsearch 6.x 部署 windows服务器。环境&#xff1a;win10elasticsearch-6.2.4springboot 2.0.0.RELEASE1. 官网下载elasticsearch这个是最新版本的es下载地址。https://www.elastic.co/downloads/elasticsearch选择z…

Programming Assignment 5: Burrows–Wheeler Data Compression

Programming Assignment 5: Burrows–Wheeler Data Compression 1. 题目阅读 实现Burrows-Wheeler数据压缩算法。这个革命性的算法产生了gzip和pkzip&#xff0c;并且相对容易实现&#xff0c;还不受任何专利保护。它构成了unix压缩实用程序bzip2的基础。 这个算法由以下三种算…

elasticsearch 6.x (二) linux部署 kibana x-pack 安装

大家好&#xff0c;我是烤鸭&#xff1a; 环境&#xff1a;linux Cent OS 7.3elasticsearch-6.2.4 1. 下载elasticsearch https://www.elastic.co/downloads/elasticsearch 上面的网址直接下载的话&#xff0c;实在太慢了。官方还提供了另一种方式。 https://www.elastic.co…

Kali Linux ——在无网络情况下安装无线网卡驱动

1、背景&#xff1a; 今日刚刚开始学习kali linux&#xff0c;众所周知&#xff0c;安装完成后&#xff0c;系统是没有无线网卡驱动的&#xff0c;这就对学生党造成相当的困扰&#xff1a;校园网要连接有线是需要认证客户端的&#xff0c;而认证客户端只有windows端&#xff0c…

HADOOP_HOME and hadoop.home.dir are unset 报错处理

一般是windows才会出现这个问题 请看下面的解决方案&#xff1a; 第一步&#xff1a;下载winutils-master.zip Gitee地址&#xff1a;https://gitee.com/nkuhyx/winutils.git 蓝奏云&#xff1a;https://www.lanzoux.com/i55ccnc Github地址&#xff1a;https://github.com/cda…

elasticsearch 6.x (三) linux 集群多节点部署

大家好&#xff0c;我是烤鸭&#xff1a;关于集群内单个节点部署&#xff0c;请参考上一篇文章。elasticsearch 6.x linux部署(二) kibana x-pack 安装环境&#xff1a;linux Cent OS 7.3elasticsearch-6.2.41. 下载多个es安装每个安装步骤都是一样的。2. 修改配置文件(重…

springboot-devtools idea或eclipse 热加载

大家好&#xff0c;我是烤鸭&#xff1a;今天分享一下springboot项目的热加载。第二种方式在eclipse和idea中都可以。虽然会有一些小坑。 方式有两种&#xff1a; 1. springloaded(无效) <!-- https://mvnrepository.com/artifact/org.springframework/springloaded -->…

springboot mybatis 热加载mapper.xml文件(最简单)

大家好&#xff0c;我是烤鸭: 今天介绍一下springboot mybatis 热加载mapper.xml文件。 本来不打算写的&#xff0c;看到网上比较流行的方式都比较麻烦&#xff0c;想着简化一下。 网上流行的版本。 https://www.cnblogs.com/oskyhg/p/8587701.html 总结一下需要&#xff1a;my…

vue cli vue 3.x

vue cli & vue 3.x https://cli.vuejs.org/dev-guide/ui-api.html#ui-api https://cli.vuejs.org/zh/guide/#cli vue cli & how to select the option in cmd ? vue cli & 选中 option a select all & i select all 1,2,3,4,5,6,7,8,9,0 分别对应 order 转载…

jenkins svn/git sonarqube scanner 代码集成测试

大家好&#xff0c;我是烤鸭&#xff1a;今天分享一个代码检测工具sonar&#xff0c;在jenkins集成的时候使用。 环境:sonarqube 7.1jenkins 2.12xsonarqube scanner &#xff08;官网最新版3.2.0.1227&#xff09;1. jenkins svn/git 搭建项目https://blog.csdn.net/Angry…

射频与微波测量之S参数

转自&#xff1a;https://www.cnblogs.com/lyh523329053/p/9128577.html S参数 S散射也叫散射参数。是微波传输中的一组重要参数。由于我们很难在高频率时测量电流或电压&#xff0c;因此我们要测量散射参数或 S 参数。这些参数用来表征RF 元件或网络的电气属性或性能&#xff…

JAVA构造对象的几种方式(构建器、构造器)

大家好&#xff0c;我是烤鸭&#xff1a;今天说一下初始化对象的几种方式&#xff1a;1. 多参数构造器2. 构建器3. 构造器后 get/set方法举个例子:这里有个机构entity&#xff0c;提供一个默认构造器 package com.xxx.xxx.modules.sys.entity;/*** 机构Entity* versi…