# HostelWorld
**Repository Path**: cuiods/HostelWorld
## Basic Information
- **Project Name**: HostelWorld
- **Description**: 基于SpringBoot+Hibernate+Spring+Swagger+Spring Security+Spring Data JPA实现的 HostelWorld 系统后端
- **Primary Language**: Java
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-03-29
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# HostelWorld
基于SpringBoot+Hibernate+Spring+Swagger+Spring Security+Spring Data JPA实现的 HostelWorld 系统后端
[系统前端](https://github.com/cuiods/HostelWorld-Front)
## Introduction
HostelWorld系统后端采用全Restful风格API,并使用Swagger UI制定了详细的API文档,运行项目后访问[http://localhost:8080/swagger-ui.html](http://localhost:8080/swagger-ui.html)就可以查看项目的所有API。
系统主要分为以下十个模块:
* /account:用户银行账户管理
* /auth:用户身份认证和登陆注销
* /check:酒店登记入住和退房管理
* /hotel:酒店创建、管理和查看相关信息
* /manager:经理审批和结算操作
* /member:会员创建和管理
* /reserve: 会员酒店预约和取消预约
* /room: 酒店房间创建和管理
* /stat: 系统数据统计
* /upload: 阿里云对象存储获取服务端签名
## Features
#### 1、使用Swagger制定API文档


#### 2、全面使用函数式编程
项目中所有的业务逻辑代码全部使用[Java8函数式编程](http://blog.csdn.net/cuiods/article/category/6603088)。
下面是数据统计方法中的一部分示例:
```java
List todayChecks = weekChecks.stream()
.filter(checkRecordEntity -> checkRecordEntity.getCreatedAt().after(yesterday))
.collect(Collectors.toList());
//set checks
statisticVo.setCheck(todayChecks.size());
long sumToday = todayChecks.stream()
.mapToLong(checkRecordEntity -> checkRecordEntity.getRoomEntity().getPrice().intValue()).sum();
long sumWeek = weekChecks.stream()
.mapToLong(checkRecordEntity -> checkRecordEntity.getRoomEntity().getPrice().intValue()).sum();
//set sum
statisticVo.setMoney(sumToday);
statisticVo.setWeekMoney(sumWeek);
weekChecks.stream()
.collect(groupingBy(check -> (check.getCreatedAt().getTime()-aWeekAgo.getTime())/86400000))
.forEach((aLong, checkRecordEntities) -> statisticVo.setChecks(aLong, checkRecordEntities.size()));
```
#### 3、 JSR-303 @Valid后端验证
采用前后端结合的方式进行输入验证,后端主要使用JSR-303 @Valid注解验证。
```java
@Data
public class CheckJson {
@NotNull
private int roomId;
private int memberId;
@Pattern(regexp = "\\d{4}-\\d{2}-\\d{2}",message = "Unsupported date format.")
private String start;
@Pattern(regexp = "\\d{4}-\\d{2}-\\d{2}",message = "Unsupported date format.")
private String end;
@Size(min = 1, max = 6, message = "tenant number should between 1 and 6")
private List tenants;
}
```
#### 4、错误码和异常处理
项目建立了完整的错误码体系。以下是几个示例:
| 错误码 | 字段 | 描述 |
| -------- | -----: | :----: |
| 420 | MEMBER_NOT_FOUND | Cannot find member. |
| 430 | ACCOUNT_CONFLICT | Not member account. |
| 440 | SCORE_NOT_ENOUGH | Not enough score for the operation. |
使用@ControllerAdvice定义全局异常处理控制器(保证返回的是包含错误信息的Json文件)
```java
@ControllerAdvice(basePackages = "edu.nju.web.controller")
@ResponseBody
public class GlobalExceptionHandler {
@ExceptionHandler(value = HostelException.class)
public ResultVo hostelExceptionHandler(HostelException exception) throws Exception {
return new ResultVo<>(exception.getCode(),exception.getMessage(),exception.getLocalizedMessage());
}
@ExceptionHandler(value = AccessDeniedException.class)
public ResultVo accessDeniedExceptionHandler(AccessDeniedException exception)
throws Exception {
return new ResultVo<>(ErrorCode.AUTHORITY_FORBIDDEN,MessageConstant.AUTHORITY_FORBIDDEN,exception.getReason()
+":"+exception.getMessage());
}
......
}
```
#### 5、Spring Security权限验证
系统用户根据角色分配有6种不同的权限,每次Http请求都会分析用户权限从而判断该操作是否可以进行。Http请求采用基本的Http Baisc Auth验证。
系统的权限包括:
| 编号 | 权限 | 描述 |
| -------- | -----: | :----: |
| 1 | USER_BASE | Basic authority of hostel user. |
| 2 | MEMBER_ACTIVE | Active member authority. |
| 3 | HOTEL_ACTIVE | Active hotel authority. |
| 4 | MEMBER_PAUSE | Suspended member authority. |
| 5 | MANAGER | Manager authority. |
| 6 | HOTEL_PAUSE | Suspended hotel authority. |
权限配置见[SecurityConfig.java](https://github.com/cuiods/HostelWorld/blob/master/src/main/java/edu/nju/web/security/SecurityConfig.java)
#### 6、Slf4j + logback日志系统
对控制器Controller方法定义切面,记录每一次请求的详细信息。
```
2017-03-14 11:51:52.750 INFO 4740 --- [http-nio-8080-exec-3] edu.nju.web.log.WebLogAspect : URL : http://localhost:8080/api/v1/manager/hotel/new
2017-03-14 11:51:52.750 INFO 4740 --- [http-nio-8080-exec-3] edu.nju.web.log.WebLogAspect : HTTP_METHOD : GET
2017-03-14 11:51:52.750 INFO 4740 --- [http-nio-8080-exec-3] edu.nju.web.log.WebLogAspect : IP : 0:0:0:0:0:0:0:1
2017-03-14 11:51:52.750 INFO 4740 --- [http-nio-8080-exec-3] edu.nju.web.log.WebLogAspect : CLASS_METHOD : edu.nju.web.controller.ManagerController.approveNewHotels
2017-03-14 11:51:52.751 INFO 4740 --- [http-nio-8080-exec-3] edu.nju.web.log.WebLogAspect : ARGS : []
2017-03-14 11:51:52.775 INFO 4740 --- [http-nio-8080-exec-3] edu.nju.web.log.WebLogAspect : RESPONSE : [HotelVo(id=22, phone=00000000000, avatar=http://hostel-world.oss-cn-shanghai.aliyuncs.com/images/avatar.png, createdAt=2017-03-10 12:44:14.0......
```
#### 7、lombok插件
使用lombok插件自动生成get、set、构造器等方法。
```java
@Data
@NoArgsConstructor
public class AccountVo {
private int id;
private Integer balance;
public AccountVo(AccountEntity accountEntity) {
BeanUtils.copyProperties(accountEntity,this,"userEntity");
}
}
```
#### 8、数据库设计
##### (1)继承
`@Inheritance(strategy = InheritanceType.JOINED)`使用JOIN继承策略,子类表只保存相对于父类额外的属性。
父类User表定义:
```java
@Entity
@Table(name = "user")
@Where(clause="deleted_at is null")
@Inheritance(strategy = InheritanceType.JOINED)
public class UserEntity {
```
子类Member表定义:
```java
@Entity
@Table(name = "member")
@PrimaryKeyJoinColumn(name = "id")
public class MemberEntity extends UserEntity{
```
##### (2)表关联与懒加载
默认获取关联表时是懒加载,调用get方法后会自动从数据库里查询出来。
```java
@OneToMany
@JoinColumn(name = "user_id")
public List getAccountEntities() {
return accountEntities;
}
```
使用`(fetch = FetchType.EAGER)`强制直接从数据库里查到相关属性,不需要调用get方法
##### (3)分页查询
```java
Sort sort = new Sort(sortDirection, sortColumn);
Pageable pageable = new PageRequest(page,pageSize,sort);
return hotelPageRepository.findAll(pageable);
```
##### (4)软删除
删除时设置deleted_at为删除时间,取出数据时要求deleted_at为null。
```java
@Where(clause="deleted_at is null")
```
#### 9、阿里云OSS后端签名
采用服务端签名的方法提高安全性。
## Get Started
1. 新建Mysql数据库hostel,导入项目根目录的hostel.sql文件
2. 编译项目,运行HostelWorldApplication中的main方法
3. 访问[http://localhost:8080/swagger-ui.html](http://localhost:8080/swagger-ui.html)查看后端API
4. 前端项目运行需要查看[系统前端](https://github.com/cuiods/HostelWorld-Front)
5. 如果需要部署,使用mvn package -Dmaven.test.skip=true打包,然后直接运行java -jar [name].jar即可。
## License
[MIT](https://tldrlegal.com/license/mit-license)