前言:

其实很早就想写这篇文章了,因为我觉得这会对很多新手有指引作用,当初自己也是瞎子过河的摸索着过来的。目前后台开发比较流行的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. pwn学习之三

    whctf2017的一道pwn题sandbox,这道题提供了两个可执行文件加一个libc,两个可执行文件是一个vuln,一个sandbox,这是一道通过沙盒去保护vuln不被攻击的题目. 用ida打开 ...

  2. 10_30_unittest

    1.断言 1).self.assertEqual(2,res)#期望值qian.结果值hou2)TextTestRunner 源码 必要的参数3)测试结果 上下文管理器 with open(" ...

  3. java实现点击图片文字验证码

    https://www.cnblogs.com/shihaiming/p/7657115.html

  4. spring 应用

    Spring框架本身会托管bean. 1.使用时需要注意对于包本身扫描配置. 2.使用注解本身包需要在扫描路径下.

  5. DRAM的原理设计

    在一个电子系统中,CPU.内存.物理存储.IO这些单元必不可少,只不过有的集成在CPU内部,有的分离出来. 这里就针对系统中的内存,此处选用DRAM来进行说明,讲述下基本的原理设计,主要分为以下几个部 ...

  6. FlowerVisor理解

    Ï来自FlowVisor: A Network Virtualization Layer这篇论文的理解 1. 简介 论文讲述如何虚拟化一个网络,并描述一个特殊的系——FlowVisor 网络虚拟化用来 ...

  7. Django ORM 知识概要

    相关命令 python3 manage.py makemigrations 根据模型生成相关迁移文件 python3 manage.py migrate 根据迁移文件,将表结构更新到数据库中,并在Dj ...

  8. CSS Sprite雪碧图

    为了减少http请求数量,加速网页内容显示,很多网站的导航栏图标.登录框图片等,使用的并不是<image>标签,而是CSS Sprite雪碧图. 两个小例子: 淘宝首页的侧栏图 代码 &l ...

  9. Winsock编程基础2(Winsock编程流程)

    1.套接字的创建和关闭 //创建套接字 SOCKET socket( int af, //指定套接字使用的地址格式,Winsock只支持AF_INET int type, //套接字类型 int pr ...

  10. VIM批量缩进

    方法一 1.按 ctrl + shif + ;  进入底行模式 2.将所要批量缩进的行号写上,按照格式:“行号1,行号2>”输入命令,如要将4至11行批量缩进一个tab值,则命令为“4,11&g ...