前言:

其实很早就想写这篇文章了,因为我觉得这会对很多新手有指引作用,当初自己也是瞎子过河的摸索着过来的。目前后台开发比较流行的MVC框架中使用Spring MVC还是比较多的,当然还有Spring Boot,Spring Boot是基于 Spring4 的条件注册的一套快速开发整合包,说白了就是简化开发流程。大家可以尝试一下,但是这里还是以Spring MVC为例子。

之所以使用jwt(json web token),是因为做后台不同于做web,app因为是长时间的登录至少都是一两个月不操作任然处于登录状态,所以目前国内大多是都是使用token做鉴权而不是使用session。而jwt是一个不错的token技术。restful就不用多说了,现在比较流行的编程风格,多个客户端(安卓,ios, mobile,web)调用同一套后台接口,而这就使得这套后台接口尽量不附带太多业务逻辑,而是面向资源的风格。而swaggerui则是提供一个rest api的可视化接口文档,并且在开发完后,可以很轻松的测试。

当然你可以只整合jwt或者swaggerui,教程都是没问题的。

所有使用到的代码可以在这里查看:https://github.com/minchangchen/springmvc-jwt-swaggerui

1.Spring MVC

Spring MVC框架是有一个MVC框架,通过实现Model-View-Controller模式来很好地将数据、业务与展现进行分离。从这样一个角度来说,Spring MVC和Struts、Struts2非常类似。Spring MVC的设计是围绕DispatcherServlet展开的,DispatcherServlet负责将请求派发到特定的handler。通过可配置的handler mappings、view resolution、locale以及theme resolution来处理请求并且转到对应的视图。这里就不做太多介绍,开始想在维基百科上搜索下spring mvc的,结果发现并没有这个条目,百度是有的。所以说有时候盈利的并不是都不好。

2.JWT(Json Web Tokens)

定义:JWT是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT作为一个开放的标准( RFC 7519 ),定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。

说明:传统的鉴权机制是基于session-cookies,而随着认证用户的增多,服务端的开销会明显增大,且不适合做app应用验证。因为app是一次登录,退出后不需登录,所以现在主流的鉴权验证都是使用token验证。而jwt是一种不错的基于token的鉴权机制。

基本流程:

用户使用用户名密码来请求服务器

服务器进行验证用户的信息

服务器通过验证发送给用户一个token

客户端存储token,并在每次请求时附送上这个token值

服务端验证token值,并返回数据

推文:http://www.jianshu.com/p/576dbf44b2ae

3.RestFul

定义:网络应用程序,分为前端和后端两个部分。当前的发展趋势,就是前端设备层出不穷(手机、平板、桌面电脑、其他专用设备......)。因此,必须有一种统一的机制,方便不同的前端设备与后端进行通信。这导致API构架的流行,甚至出现"API First"的设计思想。RESTful API是目前比较成熟的一套互联网应用程序的API设计理论。

说明:restful风格,就是一种面向资源服务的API设计方式,它不是规范,不是标准,它一种设计模式。以前流行的web service服务都是面向过程,基于RPC协议的SOAP协议,对于现在或者未来,更多的人了解并且深受SOA思想影响,以面向服务为目标,而现在的SOAP虽然支持SOA,但存在很很大的差别,所以,慢慢就流行基于restful风格的web service。说简单一点,就是它纯粹面向资源,面向服务的思想,目前J2EE6的JAX-RS就是这种restful风格实现的新技术。

例子:

获取用户列表 GET:http://project.company.com/api/v1/users
获取单个用户 GET:http://project.company.com/api/v1/users/{uid:.{32}}
创建单个用户 POST:http://project.company.com/api/v1/users/{uid:.{32}}
完全替换用户 PUT:http://project.company.com/api/v1/users/{uid:.{32}}
局部更新用户 PATCH:http://project.company.com/api/v1/users/{uid:.{32}}
删除单个用户 DELETE:http://project.company.com/api/v1/users/{uid:.{32}}

推文:http://www.ruanyifeng.com/blog/2014/05/restful_api.html

4.Swagger UI

定义:Swagger的目标是为REST APIs 定义一个标准的,与语言无关的接口,使人和计算机在看不到源码或者看不到文档或者不能通过网络流量检测的情况下能发现和理解各种服务的功能。当服务通过Swagger定义,消费者就能与远程的服务互动通过少量的实现逻辑。类似于低级编程接口,Swagger去掉了调用服务时的很多猜测。

说明:swagger ui用于管理项目中API接口,属当前最流行的API接口管理工具。是后端开发人员提供给app开发人员的一个查看、测试、的一个可视化,可操作的接口文档,在这里你可以知道需要给都太传入什么参数,使用哪种请求,以及返回的数据等等,这种就省去app端人员写测试接口。

图示:

代码:

1.maven

<!-- Spring -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>4.3.4.RELEASE</version>
	<exclusions>
		<!-- Exclude Commons Logging in favor of SLF4j -->
		<exclusion>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context-support</artifactId>
	<version>4.3.4.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
	<version>4.3.4.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-test</artifactId>
	<version>4.3.4.RELEASE</version>
</dependency>

<!-- springfox-swagger2 -->
<dependency>
	 <groupId>io.springfox</groupId>
	 <artifactId>springfox-swagger2</artifactId>
	 <version>2.5.0</version>
</dependency>
 <dependency>
	 <groupId>io.springfox</groupId>
	 <artifactId>springfox-swagger-ui</artifactId>
	 <version>2.5.0</version>
 </dependency>

 <!-- Jwt -->
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt</artifactId>
	<version>0.7.0</version>
</dependency>

2.JWT

这里我不再解释下jwt了,looking this :http://www.jianshu.com/p/576dbf44b2ae 一定要看哦!

我先说下jwt使用流程:

a:用户登录server

b:server验证通过,生成token并返回

c:app端接收到token存起来,下去请求放在reuqest的header里面

d:server接收到app的请求,在拦截器中判断url是否为需要鉴权的路径,然后去验证token

e:当token过期时,且没有超过刷新期。自动添加一个新的token返回给app

拦截器:

public abstract class BaseWebInterceptor extends HandlerInterceptorAdapter {

	public static final String RedirectPrefix = "redirect:";
	private static Logger log = LoggerFactory.getLogger(BaseWebInterceptor.class);

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		if (isNeedJwtUrl(request.getRequestURI())) {	//判断这个url是否需要jwt验证 ,比如login就不需要
			String token = request.getHeader("x-access-token");		//从request中获取token,key是自定义的,当然app端存也要是这个key
			ETokenState state = JwtUtil.validateJWT(token);			//验证token,ETokenState这是我自定义的一个类,JwtUtil这也是自己写的一个类
			switch (state) {
			case invalid:		//验证错误
				log.info(String.format("URL:%s need login, but the token is null or invalid... ", request.getRequestURL().toString()));
				response.setStatus(401);
				return false;
			case expired:		//token过期
				if (refreshTokenHandler(request, response, token)) {
					break;
				} else {
					log.info(String.format("URL:%s need login, but the token is expired... ", request.getRequestURL().toString()));
					response.setStatus(403);
					return false;
				}
			case valid:		//有效的
				break;
			default:
				break;
			}
		}
		return super.preHandle(request, response, handler);
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
		super.afterCompletion(request, response, handler, ex);
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
		super.postHandle(request, response, handler, modelAndView);
	}

	/**
	 * 刷新token,子类重载
	 *
	 * @author chenmc
	 * @date 2017年5月9日 下午3:41:05
	 * @param token
	 * @return
	 */
	protected boolean refreshTokenHandler(HttpServletRequest request, HttpServletResponse response, String token) {
		return false;
	}

	/**
	 * 需要登录的uri
	 *
	 * @param requestURI
	 * @return
	 */
	private boolean isNeedJwtUrl(String requestURI) {
		return MappingConf.isNeedJwtUrls(requestURI);
	}

}

这里需要说明的是,一般的login和register的url是不拦截的,自己可以配置。关于jwt生成和验证的代码,请点击这里https://github.com/minchangchen/springmvc-jwt-swaggerui

2.Swagger UI

配置文件:

1,springmvc.xml

<!-- swagger2 -->
	<context:component-scan base-package="com.gionee.swagger.conf"/>
	<bean class="com.company.swagger.conf.SwaggerConfig"/>
	<!-- Swagger资源重定向(仅作为后台使用不提供静态资源) -->
    <mvc:resources location="classpath:/META-INF/resources/" mapping="swagger-ui.html"/>
    <mvc:resources location="classpath:/META-INF/resources/webjars/" mapping="/webjars/**"/>

2,SwaggerConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

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;

//@Configuration
@EnableSwagger2
@EnableWebMvc
@ComponentScan("com.company.web")
public class SwaggerConfig {

    @Bean
    public Docket api(){
    	ParameterBuilder tokenPar = new ParameterBuilder();
    	List<Parameter> pars = new ArrayList<Parameter>();
		//增加一个request的header参数
    	tokenPar.name("x-access-token").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
    	pars.add(tokenPar.build());
        return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.any())
            .paths(PathSelectors.regex("/api/.*"))//对所有请求中包含api的url拦截
            .build()
            .globalOperationParameters(pars)
            .apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
            .title("后台接口文档与测试")
            .description("这是一个给app端人员调用server端接口的测试文档与平台")
            .version("1.0.0")
            .termsOfServiceUrl("http://terms-of-services.url")
            //.license("LICENSE")
            //.licenseUrl("http://url-to-license.com")
            .build();
    }

}

3,Controller

@Api(value="登录接口")
@Controller
@RequestMapping("/api/v1")
public class LoginInterface extends BaseController {

	@Autowired
	UserSO so;

	@ApiOperation(value="验证密文,并添加user", notes="密文和amigoInfo")
	@RequestMapping( value = {"/login"}, method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
	@ResponseBody
	public String login(HttpServletRequest request, @RequestParam String fields, @PathVariable String useruid) {
		// do something
	}

	/*
	*api开头的注解都是swagger的注解
	*方法参数上加有@RequestParam的参数会显示在swagger
	*所以上述login方法的三个参数只有fields会显示在swagger中
	*当然还有一个请求头的参数,存放token的那是在SaggerConfig.java中配置的
	*/
}

4,放开swagger的url不拦截

当你配置了jwt,因为jwt对url进行拦截,这里我们不能对swagger的URL进行拦截,这样页面才能正常显示。只整合swaggerui的可以忽略。

noNeedJwtUrls=.*swagger.*|.*docs.*|.*test.*|.*/index.*|.*/register.*|.*/login.*

至此,swaggerui已配置完成,请求访问http://localhost:8080/proj-name/swagger-ui.html即可得到以下页面

3.RestFul API

请参照以下这种方式来定义接口

获取用户列表 GET:http://proj.company.com/api/v1/users

获取单个用户 GET:http://proj.company.com/api/v1/users/{uid:.{32}}

创建单个用户  POST:http://proj.company.com/api/v1/users/{uid:.{32}}

完全替换用户 PUT:http://proj.company.com/api/v1/users/{uid:.{32}}

局部更新用户 PATCH:http://proj.company.com/api/v1/users/{uid:.{32}}

删除单个用户 DELETE:http://proj.company.com/api/v1/users/{uid:.{32}}

至此,所有配置应该都已经贴出,代码可在这里查找:https://github.com/minchangchen/springmvc-jwt-swaggerui


若有遗失或错误希望大家提出!过段时间我会写一些与docker有关的教程,这段时间觉得自己对docker的使用还不够全及精,所以暂时不写!

SpringMVC+JWT+Swagger UI+RestFul的更多相关文章

  1. SpringMVC融合Swagger UI使用

    相信大家都很熟悉springmvc,在用其进行开发工作的时候,有没有遇到几个小问题?比如: 1.前后端分离的模式下,前端开发人员如何得知后端的开发进度,有哪些接口可用? 2.后端开发人员在测试自己的接 ...

  2. gRPC helloworld service, RESTful JSON API gateway and swagger UI

    概述 本篇博文完整讲述了如果通过 protocol buffers 定义并启动一个 gRPC 服务,然后在 gRPC 服务上提供一个 RESTful JSON API 的反向代理 gateway,最后 ...

  3. Swagger UI 与SpringMVC的整合 II

    pom.xml <!-- swagger开始 --> <dependency> <groupId>io.springfox</groupId> < ...

  4. 使用 Swagger UI 与 Swashbuckle 创建 RESTful Web API 帮助文件

    作者:Sreekanth Mothukuru 2016年2月18日 本文旨在介绍如何使用常用的 Swagger 和 Swashbuckle 框架创建描述 Restful API 的交互界面,并为 AP ...

  5. 使用 Swagger UI 与 Swashbuckle 创建 RESTful Web API 帮助文件(转)

    作者:Sreekanth Mothukuru2016年2月18日 本文旨在介绍如何使用常用的 Swagger 和 Swashbuckle 框架创建描述 Restful API 的交互界面,并为 API ...

  6. springMVC整合swagger(亲自试验完全可用)

    swagger是什么: [plain] view plain copy Swagger 是一款RESTFUL接口的文档在线自动生成+功能测试功能软件.本文简单介绍了在项目中集成swagger的方法和一 ...

  7. Swagger: 一个restful接口文档在线生成+功能测试软件

    一.什么是 Swagger? Swagger 是一款RESTFUL接口的文档在线自动生成+功能测试功能软件.Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 ...

  8. Yii2+Swagger搭建RESTful风格的API项目

    在现有的Advanced Template上搭建RESTful API项目的步骤: 本案例前提说明: 本例中不使用\yii\rest\ActiveController自动创建的API,而是自定义一个A ...

  9. spring-mvc集成 swagger

    问题1:spring-mvc集成 swagger, 配置好后界面 404, 原因: dispatcher-servlet.xml 文件中, 要在这上面 <!-- 启用spring mvc 注解 ...

随机推荐

  1. Canvas 获得键盘焦点的方法

    Canvas 无法直接获得键盘焦点,但可以通过设置 tabindex 属性的方式获得焦点,实现代码如下: canvas.setAttribute('tabindex', '0'); // needed ...

  2. pycharm创建scrapy项目教程及遇到的坑

    最近学习scrapy爬虫框架,在使用pycharm安装scrapy类库及创建scrapy项目时花费了好长的时间,遇到各种坑,根据网上的各种教程,花费了一晚上的时间,终于成功,其中也踩了一些坑,现在整理 ...

  3. ElasticSearch本人启动报错总结

    1.报错关键代码如下: Exception in thread "main" 2019-04-28 03:53:04,339 main ERROR No log4j2 config ...

  4. JAVA基础复习与总结<五> String类_File类_Date类

    String类 .Java字符串就是Unicode字符序列,例如串“Java”就是4个Unicoe字符组成. .Java没有内置的字符串类型,而是在标准java类库中提供了一个预定义的类String, ...

  5. 为什么目前无法再docker for windows中调用GPU

    本随笔记载与2019年1月23日,若随着技术发展,本随笔记录的困难被攻克也是可能的. 参考(https://www.reddit.com/r/docker/comments/86vzna/gpu_ac ...

  6. Android Studio的构建系统:Gradle

    原文作者:youxiachai <用Gradle 构建你的android程序> 前言 android gradle 的插件终于把混淆代码的task集成进去了,加上最近,android st ...

  7. 1.SSM整合_单表的增删改查

    目标:增删改查 环境:Maven+Eclipse+Tomcat7+JDK7 思维导图: 表结构 目录结构 依赖 <dependencies> <dependency> < ...

  8. A_B_Good Bye 2018_cf

    A. New Year and the Christmas Ornament time limit per test 1 second memory limit per test 256 megaby ...

  9. 压力测试工具 ab

    ab 是Apache 自带的一个压力测试工具,命令行,是 ApacheBench 命令的缩写. ab的原理:ab命令会创建多个并发访问线程,模拟多个访问者同时对某一URL地址进行访问.它的测试目标是基 ...

  10. cadence钻孔文件及光绘文件的生成

    完成PCB布线之后,需要生成钻孔文件和光绘文件交给PCB厂家制作PCB板,下面总结详细方法!