NightFlightCaptain / Ssm

Licence: apache-2.0
👅基于RESTful风格的前后端分离的SSM框架,集成了shiro和swagger等框架

Programming Languages

java
68154 projects - #9 most used programming language

Projects that are alternatives of or similar to Ssm

Spring Boot Plus
🔥 Spring-Boot-Plus is a easy-to-use, high-speed, high-efficient,feature-rich, open source spring boot scaffolding. 🚀
Stars: ✭ 2,198 (+1458.87%)
Mutual labels:  swagger, redis, jwt, shiro
Swagger Express Ts
Generate and serve swagger.json
Stars: ✭ 102 (-27.66%)
Mutual labels:  rest-api, rest, swagger, swagger2
Node Express Mongoose Passport Jwt Rest Api Auth
Node, express, mongoose, passport and JWT REST API authentication example
Stars: ✭ 146 (+3.55%)
Mutual labels:  rest-api, rest, restful, jwt
Node Typescript Mongodb
node js typescript mongodb express generator yo
Stars: ✭ 96 (-31.91%)
Mutual labels:  rest-api, rest, swagger, restful
Codeigniter Jwt Sample
CodeIgniter JWT Sample
Stars: ✭ 144 (+2.13%)
Mutual labels:  rest-api, rest, restful, jwt
Springboot Learn
🌹springboot常用框架整合示例,涉及多种网站监控,数据缓存,网络通信,持久层,权限管理,常用工具等
Stars: ✭ 270 (+91.49%)
Mutual labels:  swagger2, redis, jwt, shiro
X Admin
致力于快速开发中小型后台管理系统项目模板(更新中......)
Stars: ✭ 123 (-12.77%)
Mutual labels:  swagger2, redis, jwt, shiro
Swagger Inflector
Stars: ✭ 131 (-7.09%)
Mutual labels:  rest-api, rest, swagger
Ngx Api Utils
ngx-api-utils is a lean library of utilities and helpers to quickly integrate any HTTP API (REST, Ajax, and any other) with Angular.
Stars: ✭ 92 (-34.75%)
Mutual labels:  rest-api, rest, jwt
Go Codon
Workflow based REST framework code generator
Stars: ✭ 133 (-5.67%)
Mutual labels:  rest-api, rest, swagger
Train Ai With Django Swagger Jwt
Train AI (Keras + Tensorflow) to defend apps with Django REST Framework + Celery + Swagger + JWT - deploys to Kubernetes and OpenShift Container Platform
Stars: ✭ 66 (-53.19%)
Mutual labels:  rest-api, swagger, jwt
Http restful api
整理HTTP后台端的RESTful API方面的知识
Stars: ✭ 94 (-33.33%)
Mutual labels:  rest-api, rest, restful
Parsevip
解析VIP资源,解析出酷狗、QQ音乐、腾讯视频、人人视频的真实地址
Stars: ✭ 105 (-25.53%)
Mutual labels:  redis, jwt, shiro
Jeeplatform
一款企业信息化开发基础平台,拟集成OA(办公自动化)、CMS(内容管理系统)等企业系统的通用业务功能 JeePlatform项目是一款以SpringBoot为核心框架,集ORM框架Mybatis,Web层框架SpringMVC和多种开源组件框架而成的一款通用基础平台,代码已经捐赠给开源中国社区
Stars: ✭ 1,285 (+811.35%)
Mutual labels:  restful, redis, shiro
Spring Boot Sample App
Sample app generated from my spring boot archtype on :https://github.com/Romeh/spring-boot-quickstart-archtype
Stars: ✭ 81 (-42.55%)
Mutual labels:  rest-api, swagger, swagger2
Jersey Jwt
Example of REST API with JWT authentication using Jersey, Jackson, Undertow, Weld, Hibernate and Arquillian.
Stars: ✭ 131 (-7.09%)
Mutual labels:  rest-api, rest, jwt
Restfm
RESTful web services for FileMaker server.
Stars: ✭ 76 (-46.1%)
Mutual labels:  rest-api, rest, restful
Gemini
Model Driven REST framework to automatically generate CRUD APIs
Stars: ✭ 138 (-2.13%)
Mutual labels:  rest-api, rest, swagger
Spring Boot Shiro
Shiro基于SpringBoot +JWT搭建简单的restful服务
Stars: ✭ 1,563 (+1008.51%)
Mutual labels:  restful, jwt, shiro
Skill6 Website Backend
java进阶开发,高级版web项目。基于dubbo实现分布式微服务架构,基于spring boot、spring mvc、mybatis、docker、ELK、redis、vue.js、node.js等技术实现的技术分享交流网站。网站名称:技术流,英文名:skill6。主要功能有:登录注册、单点登录、restful设计、文章及评论、代码及资源下载、主题讨论等。持续更新中...
Stars: ✭ 140 (-0.71%)
Mutual labels:  restful, redis, shiro

基本框架

基础的SSM框架,集成了shiro作为登陆验证和权限管理和swagger作为开接口文档,让后端程序员专注于业务的开发


1、前后端分离思想

其实前后端分离并不只是开发模式,而是web应用的一种架构模式,前后端之前使用HTTP或者其他协议进行交互请求。后端负责业务/数据接口,前端负责展现/交互逻辑,前后端开发并行且独立。 随着发展,前后端分离也不局限于web开发,越来越向一对多的方向发展。对于同一份数据接口,我们可以定制开发多个客户端,比如web和app就可以使用同一个接口,多个前端展示。


2、如何实现前后端分离

简单来说,前端使用AJAX请求后台接口,后台都数据进行处理后返回给前端,这个过程我们多半使用json格式来传递数据(也可以使用XML等),而对于前端使用Vue、React、Angular甚至Jquery都是没有关系的,同样对后端的开发语言也没有限制


3、RESTful风格

首先,REST不是休息的意思,是一种接口开发设计规范,是Representational State Transfer的缩写,其意为“表现层状态转化”,省略了主语。"表现层"其实指的是"资源"(Resources)的"表现层"。REST认为,每一个URL都是一种资源,所有的操作都是对资源的操作,而不同的操作主要使用HTTP动词来表示,我们都知道HTTP有get和post方法,并理解他们的简单区别,但是实际上,http远不止这两种,还有其他的方法:

方法 含义
GET(SELECT) 从服务器取出资源(一项或多项)
POST(CREATE) 在服务器新建一个资源
PUT(UPDATE) 在服务器更新资源(客户端提供改变后的完整资源)
DELETE(DELETE) 从服务器删除资源
HEAD 获取资源的元数据
OPTIONS 获取信息,关于资源的哪些属性是客户端可以改变的

主要使用的前4种方法,分别对应着“查、增、改、删”。每一项都是对资源的操作。具体的详细解释可以参考阮一峰先生所讲的《理解RESTful架构》 《RESTful API 设计指南》 下面给出一些例子:

方法 含义
GET /zoos 列出所有动物园
POST /zoos 新建一个动物园
GET /zoos/ID 获取某个指定动物园的信息
PUT /zoos/ID 更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH /zoos/ID 更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE /zoos/ID 删除某个动物园
GET /zoos/ID/animals 列出某个指定动物园的所有动物
DELETE /zoos/ID/animals/ID 删除某个指定动物园的指定动物

下面就说一下具体的实现与配置

4、统一响应结构

使用REST框架实现前后端分离架构,我们需要首先确定返回的JSON响应结构是统一的,也就是说,每个REST请求将返回相同结构的JSON响应结构。定义一个相对通用的JSON响应结构,其中包含两部分:元数据与返回值,其中,元数据表示操作是否成功与返回值消息等,返回值对应服务端方法所返回的数据。该JSON响应结构如下:

{
  "code": 200,
  "message": "success",
  "data": {}
}

可以在每次返回时候根据实际情况返回数据

{
  "code": 200,
  "message": "成功查询用户",
  "data": {
    "user": {
      "id": 1,
      "account": "test_user",
      "password": "123456"
          }
  }
}

下面给出JAVA中的代码

public class Msg {

	private int code;

	private String message;

	private Map<String,Object> data = new HashMap<String, Object>();

	private Msg(int code, String message) {
		this.code = code;
		this.message = message;
	}

	public static Msg message(int code,String message){
		Msg result = new Msg(code,message);
		return result;
	}
	/**
	 * 处理成功时返回的数据
	 * @return
	 */
	public static Msg success(){
		Msg result = new Msg(200,"处理成功");
		return result;
	}

	public static Msg success(String message){
		Msg result = new Msg(200,message);
		return result;
	}

	public static Msg error(){
		Msg result = new Msg(400,"处理失败");
		return result;
	}
	public static Msg error(String message){
		Msg result = new Msg(400,message);
		return result;
	}

	/**
	 * 添加封装的数据,实现链式编程
	 * @param key
	 * @param value
	 * @return
	 */
	public Msg add(String key,Object value){
		this.data.put(key,value);
		return this;
	}

	public int getCode() {
		return code;
	}

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

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Map<String, Object> getData() {
		return data;
	}

	public void setData(Map<String, Object> data) {
		this.data = data;
	}

	@Override
	public String toString() {
		return "Msg{" +
				"code=" + code +
				", message='" + message + '\'' +
				", data=" + data +
				'}';
	}
}

值得一提的是,我在Msg中没有完全封装data返回值,而是在每次返回的时候手动添加“data”,这是因为我采用了HashMap的结构,可以使用add方法可以不断添加需要的返回值,实现链式编程

对于前后端之间如何传输json数据,在spring中有相应的注解来解决这一问题,在返回的时候可以使用@ResponseBody来将返回的数据序列化成json,在使用Post方法或Put方法时,也可以使用@RequestBody来将json数据转换成JAVA中的对象。 顺便提一下 可以采用@RestController实现@Controller和@ResponseBody的合并效果


5、统一异常处理

在代码中我们经常需要捕获异常,如果我们在每一个方法里面进行try catch来捕获可能出现的异常是十分麻烦的,所以我们可以采用@ControllerAdvice定义一个增强的控制器来处理全局异常。

/**
 *
 * 全局异常处理,所有的异常都放在这里进行处理,无需在每个地方try catch
 *
 * Copyright(C) 2018-2018
 * Author:wanhaoran
 * Date: 2018/6/1 8:37
 */
@RestControllerAdvice
public class ExceptionAdvice {

	private static final Logger LOGGER = LogManager.getLogger(UserRealm.class);
	/**
	 * 信息无法读取
	 * @param e
	 * @return
	 */
	@ExceptionHandler(HttpMessageNotReadableException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public Msg handleHttpMessageNotReadableException(Exception e){
		e.printStackTrace();
		return Msg.message(400,"无法读取");
	}

	/**
	 * 处理参数异常
	 * @param e
	 * @return
	 */
	@ExceptionHandler(MethodArgumentNotValidException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public Msg handleMethodArgumentNotValidException(Exception e){
		return Msg.message(400,"参数验证失败");
	}

	/**
	 * 处理自定义异常
	 * @param e
	 * @return
	 */
	@ExceptionHandler(IException.class)
	@ResponseStatus(HttpStatus.EXPECTATION_FAILED)
	public Msg handleIException(IException e){
		return Msg.message(417,"自定义异常");
	}

	/**
	 * 数学计算错误
	 * @param e
	 * @return
	 */
	@ExceptionHandler(ArithmeticException.class)
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public Msg handleArithmeticException(ArithmeticException e){
		return Msg.message(500,"服务器内部错误");
	}

	/**
	 * 登陆错误
	 * @param e
	 * @return
	 */
	@ExceptionHandler(AuthenticationException.class)
	@ResponseStatus(HttpStatus.UNAUTHORIZED)
	public Msg handleAuthenticationException(AuthenticationException e){
		LOGGER.error(e);
		return Msg.message(401,"登陆错误");
	}

	@ExceptionHandler(UnknownAccountException.class)
	@ResponseStatus(HttpStatus.UNAUTHORIZED)
	public Msg handleUnknownAccountException(UnknownAccountException e){
		LOGGER.error(e);
		return Msg.message(401,"请登录");
	}


	/**
	 * 没有权限——shiro
	 * @param e
	 * @return
	 */
	@ExceptionHandler(UnauthorizedException.class)
	@ResponseStatus(HttpStatus.FORBIDDEN)
	public Msg handleUnauthorizedException(UnauthorizedException e){
		return Msg.message(403,"没有权限");
	}
}

定义个带有@ControllerAdvice的这个类之后,在其中可以写对于异常的处理,在方法上使用@ExceptionHandler注解决定处理哪一种异常,而@ResponseStatus用来决定返回的HTTP状态码,之后我们返回给前端的数据也还是Msg的结构,里面包含了发生的异常的相关信息,前端就可以进行相应的处理,提醒用户进行正确的操作,而不是单纯的报错,提升用户体验。 此外:在这个类中@ExceptionHandler的位置,是从上到下依次检查的,如果你在前面定义了@ExceptionHandler(Exception.class)进行处理,那么后面定义的对于Exception的子类的处理就全部无效了。

我们还可以根据需要设计自己的异常类。

/**
 *
 * 自定义异常
 *
 * Copyright(C) 2018-2018
 * Author: wanhaoran
 * Date: 2018/6/1 8:29
 */
public class IException extends RuntimeException{
	private static final long serialVersionUID = 7144771828212718116L;
	private String message;

	public IException(String message){
		this.message = message;
	}

	@Override
	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
}

可以在相应的地方抛出自定义异常然后被ControllerAdvice定义的类中的方法捕获。


6、参数验证

  @RequiresPermissions("user:add")
	@ApiOperation(value = "新增用户", notes = "根据用户对象来新增")
	@PostMapping()
	public Msg addUser(@RequestBody @Valid SysUser sysUser) throws Exception{
		sysUserService.addUser(sysUser);
		return Msg.message(201,"成功新增用户");
	}

比如对于这个方法,我们需要获取一个SysUser,但是前端传来的并不一定是合理的数据,虽然前端也可以做一些验证,但并不可靠,对于隐私数据,后端还需要再做一次验证。那我们需要一个个判断吗,当然不是,我们可以使用Hibernate Validator来实现(此处的Hibernate和SSH中的Hibernate不是同一个东西)。例如我们需要这个前端传来的SysUser的账户名不能为空、密码不能少于6位等需求。就可以在获取的对象前面加上@Valid注解,同时在SysUser中对于的成员变量加入注解

@NotEmpty(message = "姓名不能为空")
private String account;

@Length(min = 6,message = "密码不能少于6位")
private String password;

就可以自动的进行验证 然后在前面所说的全局异常处理器中处理这个异常

	/**
	 * 处理参数异常
	 * @param e
	 * @return
	 */
	@ExceptionHandler(MethodArgumentNotValidException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public Msg handleMethodArgumentNotValidException(Exception e){
		return Msg.message(400,"参数验证失败");
	}

如果我们提供不符合要求的数据,那么就会返回如下结果

{
"code": 400,
"message": "参数验证失败",
"data": {}
}

7、接口文档自动生成

每次写完接口之后,都还要写相应的接口文档与他人协调与测试,这个过程是十分繁琐切复杂的,而且对于每一次接口的修改都要修改相应的接口文档。为了解决这个问题,我们可以集成spring和swagger,swagger可以帮助我们根据Controller自动生成相应的接口文档,我们只需要使用注解来对接口文档进行说明就可以了。这样可以省下一大笔时间,而且每次修改后swagger也会相应的更改,再也不用担心接口更改但是接口文档没有更改的情况了。 我们需要定义一个swagger-config类来设计swagger的相关配置

**
 *
 * 集成Swagger2的页面配置
 *
 * Copyright(C) 2018-2018
 * Author: wanhaoran
 * Date: 2018/5/31 16:05
 */
//@Configuration //这里需要注意,如果项目架构是SSM,那就不要加这个注解,如果是 spring boot 架构类型的项目,就必须加上这个注解,让 spring 加载该配置。
@EnableWebMvc // spring boot 项目不需要添加此注解,SSM 项目需要加上此注解,否则将会报错。
@EnableSwagger2
public class SwaggerConfig {
	@Bean
	public Docket buildDocket(){
		return new Docket(DocumentationType.SWAGGER_2)
				.apiInfo(buildApiInfo())
				.select().apis(RequestHandlerSelectors.basePackage("controller"))// controller路径。
				.paths(PathSelectors.any())
				.build();
	}

	// 配置 API 文档标题、描述、作者等等相关信息。
	private ApiInfo buildApiInfo(){
		return new ApiInfoBuilder()
				.title("前后端分离系统API接口文档")
				.termsOfServiceUrl("")
				.description("Spring MVC中使用Swagger2构建Restful API")
				.build();

	}
}

然后将其加载到容器当中,在springmvc.xml中输入 <beanclass="common.SwaggerConfig"/> 具体的swagger注解如何使用可以参考:注解的使用说明

swagger页面

8、shiro的集成

关于shiro

shiro是目前流程轻便的安全框架,用来解决登陆认证和权限管理等问题,具体的解释小伙伴们可以自行google,就不对shiro的含义展开详细论述了 对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的Shiro就足够了。对于它俩到底哪个好,这个不必纠结,能更简单的解决项目问题就好了。

shiro中的会话管理和权限管理

用户第一次访问受限的资源时,shiro会去加载用户能访问的所有权限标识。默认情况下,shiro并未缓存这些权限标识。当再次访问受限的资源时,还会去加载用户能访问的权限标识。 当请求多时,这样处理显然会影响性能,因此需要为shiro加缓存。shiro本身内置有缓存功能,需要配置启用它。shiro为我们提供了两个缓存实现,一个是基于本地内存(org.apache.shiro.cache.MemoryConstrainedCacheManager),另一个是基于EhCache(org.apache.shiro.cache.ehcache.EhCacheManager)。这两套实现都只适合单机玩,当在分布式环境下效果就不理想了。 于是采用了一套基于redis的shiro缓存实现,便于分布式的需求,具体的配置可以直接查看源代码文件


说明

  • 在源代码里,所有的配置文件中都有详细的注释,如果有需求的话可以直接查看和学习
  • 有什么疑问或者发现了项目中的问题可以直接和我发email练习
  • 如果项目对你有所帮助,请点击一个star
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].