博客说明:撰写博客目的是在记录自己所学知识、在工作中使用技术遇到的技术问题、一些技术感悟,因此避免不了涉及到和其他文章有相似之处。本文从作者自己的实践中指出相关踩坑问题,着重指出学习过程中遇到的相关问题。如果存在相关侵权问题请联系博主删除,同时有技术上的见解可以在评论去里发出,会不定期回复,谢谢。
gitee地址:https://gitee.com/woniurunfast/springbootwitheverything
在企业SpringBoot的日常开发中,请求除了请求参数外,还有header,同时经常开发中会用到拦截器处理某些接口(如鉴权等),因此本文实现头拦截器,请求某接口时候拦截Header参数
1、创建拦截器拦截请求指定路径接口的Header
1、创建自己设置的RequestHeader类
package com.hkx.demo.common; import lombok.Data; import java.io.Serializable; @Data public class RequestHeader implements Serializable{ private String tocken; private String empno; private String lang; }
2、为方便调试,在swagger中引入header传参的设置
/** * itbooking系统平台<br/> * com.itbooking.config<br/> * SweggerConfiguration.java<br/> * 创建人:mofeng <br/> * 时间:2018年9月24日-下午5:35:07 <br/> * 2018itbooking-版权所有<br/> */ package com.hkx.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.ParameterBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.schema.ModelRef; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Parameter; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.ArrayList; import java.util.List; @Configuration @EnableSwagger2 public class SwaggerConfiguration { /** * 在完成上述配置之后,其实就已经可以产生帮助文档了,但是这样的文档主要针对请求本身,而描述主要来源于函数等命名产生。 * 对用户体验不好,我们通常需要自己增加一些说明来丰富文档内容。如果: * 加入 * * @ApiIgnore 忽略暴露的 api * @ApiOperation(value = "查找", notes = "根据用户 ID 查找用户") * 添加说明 * <p> * <p> * 其他注解: * @Api :用在类上,说明该类的作用 * @ApiImplicitParams :用在方法上包含一组参数说明 * @ApiResponses :用于表示一组响应 * 完成上述之后,启动springboot程序, * 旧访问:http://localhost:8080/swagger-ui.html * 新访问:http://localhost:8080/doc.html * @ApiOperation() 用于方法;表示一个http请求的操作 * value用于方法描述 * notes用于提示内容 * tags可以重新分组(视情况而用) * @ApiParam() 用于方法,参数,字段说明;表示对参数的添加元数据(说明或是否必填等) * name–参数名 * value–参数说明 * required–是否必填 * @ApiModel()用于类 ;表示对类进行说明,用于参数用实体类接收 * value–表示对象名 * description–描述 * 都可省略 * @ApiModelProperty()用于方法,字段; 表示对model属性的说明或者数据操作更改 * value–字段说明 * name–重写属性名字 * dataType–重写属性类型 * required–是否必填 * example–举例说明 * hidden–隐藏 * @ApiIgnore()用于类或者方法上,可以不被swagger显示在页面上 比较简单, 这里不做举例 * @ApiImplicitParam() 用于方法 * 表示单独的请求参数 * @ApiImplicitParams() 用于方法,包含多个 @ApiImplicitParam * name–参数ming * value–参数说明 * dataType–数据类型 * paramType–参数类型 * example–举例说明 */ @Bean @Profile("dev") public Docket createRestApi() { ParameterBuilder tocken = new ParameterBuilder(); ParameterBuilder lang = new ParameterBuilder(); ParameterBuilder empNo = new ParameterBuilder(); List<Parameter> paras = new ArrayList<>(); //默认请求头设置 tocken.name("W-Auth-number").defaultValue("tocken值").modelRef(new ModelRef("String")).parameterType("header").required(true).build(); lang.name("W-Lang-Select").defaultValue("语言选择").modelRef(new ModelRef("String")).parameterType("header").defaultValue("zh_CN").required(true).build(); empNo.name("W-Emp-number").defaultValue("用户ID").modelRef(new ModelRef("String")).parameterType("header").required(true).build(); paras.add(tocken.build()); paras.add(lang.build()); paras.add(empNo.build()); return new Docket(DocumentationType.SWAGGER_2) .apiInfo(getApiInfo()) .select() // 核心:读取把那个包下面的方法作为接口,只能是:controller .apis(RequestHandlerSelectors.basePackage("com.hkx.demo.controller")) .paths(PathSelectors.any()) .build() .globalOperationParameters(paras); } private ApiInfo getApiInfo() { return new ApiInfoBuilder() .title("项目数据接口") .description("项目数据接口,在线体验文档") .termsOfServiceUrl("https://api.hkx.com/api") .version("1.0") .build(); } }
3、创建HeaderUtil在每个线程中保存使用Header
package com.hkx.demo.util; import com.hkx.demo.common.RequestHeader; import lombok.extern.slf4j.Slf4j; import java.util.HashMap; import java.util.Map; @Slf4j public class HeaderUtil { private static final Map<String,String> LANGUAGE_COMPATIABLE = new HashMap<String, String>(){ { put("en_US".toLowerCase(),"en_US"); put("zh_CN".toLowerCase(),"en_US"); } }; public static final String ZH_CN = "zh_CN"; public static final String EN_US = "en_US"; private static ThreadLocal<RequestHeader> requestHeader = new ThreadLocal<>(); public static void setRequestHeader(RequestHeader requestHeader){ if (requestHeader != null){ remove(); } HeaderUtil.requestHeader.set(requestHeader); } private static void remove() { requestHeader.remove(); } public static String getTocken(){ return HeaderUtil.requestHeader.get().getTocken(); } public static String getEmpNo(){ return HeaderUtil.requestHeader.get().getEmpno(); } public static String getLanguage(){ if (HeaderUtil.requestHeader.get()==null){ log.error("no header"); return ZH_CN; } String lang = HeaderUtil.requestHeader.get().getLang(); if (lang!=null){ return LANGUAGE_COMPATIABLE.getOrDefault(lang.toLowerCase(),lang); }else { log.error("no header"); return ZH_CN; } } }
4、创建Header拦截器
package com.hkx.demo.common; import com.hkx.demo.constant.SysGlobalConst; import com.hkx.demo.util.HeaderUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Slf4j @Component public class HeaderInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { setRequestHeaderInfo(request); log.info("拦截成功"); return true; } private void setRequestHeaderInfo(HttpServletRequest request) { RequestHeader requestHeader = new RequestHeader(); requestHeader.setTocken(request.getHeader(SysGlobalConst.HTTP_TOKEN)); requestHeader.setEmpno(request.getHeader(SysGlobalConst.HTTP_EMPNO)); requestHeader.setLang(request.getHeader(SysGlobalConst.HTTP_LANG)); //HeaderUtil是header在线程中的保存的工具类,方便线程中使用 HeaderUtil.setRequestHeader(requestHeader); } }
5、注册拦截器
package com.hkx.demo.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired HandlerInterceptor handlerInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { //表示只拦截路径是/select/下面的接口 registry.addInterceptor(handlerInterceptor).addPathPatterns("/select/*"); } }
在接口访问控制层中添加拦截的Header输出:
package com.hkx.demo.controller; import com.hkx.demo.common.Result; import com.hkx.demo.entity.WoNiu; import com.hkx.demo.util.HeaderUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/select") @Slf4j @Api("测试返回结果") public class ResultController { @ApiOperation("结果测试") @GetMapping("/getWoniu") public Result getUser2(Integer id) { log.info("--------"); WoNiu user = new WoNiu(); user.setId(1); user.setHobby("swim"); user.setDesc("just for fun"); user.setType("happy"); //将拦截的Header的员工号输出 System.out.println(HeaderUtil.getEmpNo()); return Result.success(user); } }
调接口
结果: