快速構建一個簡單的Springboot-web專案
阿新 • • 發佈:2021-07-01
web專案基本的核心成分
- 資料落地 MYSQL資料庫
- 登入標識 JWT :{Java web token }
- 記錄有效登入狀態 以及快取常用資料: Redis
- 資料庫與JAVA實體的快速自動對映ORM:mybatis
- 資料庫連線池化技術:Druid
- 檢視解析器模板引擎:Thymeleaf
- 基於介面測試和介面文件工具:Swagger
- 單元測試:Junit
- 實體類簡化工具:lombok
- SpringbootTest:
POM檔案如下:
SpringBoot主版本:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.gton</groupId> <artifactId>hander</artifactId> <version>1.0-SNAPSHOT</version> <!-- JDK-版本:編碼設定--> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--Mybatis ORM--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <!--德魯伊資料庫連線池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.6</version> </dependency> <!--mysql 驅動--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- thymeleaf 模板引擎-檢視解析器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!--單元測試--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!--Springboot Test--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!--lombok--> <!-- lombok-實體類簡化依賴--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> <!-- swagger2 介面API文件 介面測試 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> <!--JWT登入認證--> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.11.0</version> </dependency> <!-- redis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies> <build> <!--xml-mapper 資源過濾--> <resources> <resource> <directory>src/main/resource</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build> </project>
YML核心配置檔案內容如下
server: port: 8888 spring: application: name: springboot-app datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/study?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false username: root password: root druid: test-while-idle: false #Springboot 整合redis資料庫 redis: host: 127.0.0.1 port: 6379 password: 123456 jedis: pool: max-active: 8 max-wait: -1 max-idle: 500 min-idle: 0 lettuce: shutdown-timeout: 0 thymeleaf: cache: false #關閉快取,即使重新整理 預設 true,關閉之後可以及時重新整理頁面 mode: HTML5 #預設 HTML5 encoding: UTF-8 # 預設 UTF-8 prefix: classpath:/templates/ #預設 classpath:/templates/ suffix: .html # 預設 .html mvc: static-path-pattern: classpath:/static/** mybatis: config-location: classpath:maybati-config.xml mapper-locations: classpath:mapper/*.xml
YML外部引用了Mybatis-config配置檔案和指定了Mapper掃描路徑;
Mybatis-config:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--開啟二級快取--> <settings> <!--開啟二級快取--> <setting name="cacheEnabled" value="true"/> <!--配置日誌輸出--> <setting name="logImpl" value="STDOUT_LOGGING" /> <!--開啟駝峰欄位自動轉化--> <setting name="mapUnderscoreToCamelCase" value="true" /> </settings> <!--配置別名--> <typeAliases> <package name="com.entity"/> </typeAliases> </configuration>
啟動器
@SpringBootApplication
@EnableTransactionManagement //1.開始事物宣告式註解處理
public class ApplicationRun {
public static void main(String[] args) {
SpringApplication.run(ApplicationRun.class, args);
}
}
專案目錄結構
使用SWagger,需要配置
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.pathMapping("/")
.select()
.apis(RequestHandlerSelectors.basePackage("com.controller"))
.paths(PathSelectors.any())
.build().apiInfo(new ApiInfoBuilder()
.title("SpringBoot整合Swagger介面測試")
.description("SpringBoot整合Swagger,詳細資訊......")
.version("1.0")
//new Contact("暱稱", "網址連結", "郵箱"))
.contact(new Contact("隔壁老郭", "https://www.cnblogs.com/gtnotgod/", "[email protected]"))
.license("The Apache License")
.licenseUrl("http://www.baidu.com")
.build());
}
}
Swagger配置還沒完,還要開啟靜態資源過濾
@Configuration
public class webMvcConfig implements WebMvcConfigurer {
/**
* Description: 靜態資源過濾
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//ClassPath:/Static/** 靜態資源釋放
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
//釋放swagger
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
//釋放webjars
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
Controller:
@RestController
@Slf4j
@Api(value = "SpringBoot-CRUD-Demo", tags = "基於SpringBoot的增刪改查示例Controller")
public class UserController {
@Autowired
private UserService userService;
/**
* Description: http://localhost:8888/getList
*/
@GetMapping(value = "/getList", name = "全部獲取資料")
@ApiOperation("全部獲取資料-介面")
public RespObject getListByNotLimit() {
List<UserTable> users = userService.getUsers();
return RespObject.respOk(users);
}
/**
* Description: http://localhost:8888/getListById?id=1001
*/
@GetMapping(value = "/getListById", name = "根據ID獲取資料")
@ApiOperation("根據ID獲取資料-介面")
public RespObject getUserTable(@RequestParam("id") int id) {
UserTable user = userService.getUserById(id);
if (user == null) {
return RespObject.respNo("輸入的ID無效");
}
return RespObject.respOk(user);
}
/**
* Description: http://localhost:8888/getUsersByLimit?currentPage=1&pageSize=10
* select * from table limit (start-1)*pageSize,pageSize;
* mysql 分頁第一個引數是index{0-max},第二個引數是取的數量
*/
@GetMapping(value = "/getUsersByLimit", name = "分頁查詢")
@ApiOperation("分頁查詢-介面")
public RespObject getUserTableByLimit(@RequestParam("currentPage") int currentPage, @RequestParam("pageSize") int pageSize) {
log.info("每一頁分:" + pageSize + "條" + ";請求的第:" + currentPage + "頁");
if (currentPage == 0) {
return RespObject.respNo("首頁座標是從1開始");
}
List<UserTable> limitUsers = userService.getUserByLimit((currentPage - 1) * pageSize, pageSize);
return RespObject.respOk(limitUsers);
}
/**
* Description: 新增操作
*/
@PostMapping(value = "/addUserTable", name = "新增表資料")
@ApiOperation("新增表資料-介面")
public RespObject addUserTableData(@RequestBody UserTable userTable) {
System.out.println(userTable);
int id = userTable.getId();
//判斷ID是否存在-{isPresent存在就返回true}
if (id != 0) {
return RespObject.respNo("新增操作不允許傳遞主鍵");
}
int rowChange = 0;
try {
rowChange = userService.insertInToUserTable(userTable);
} catch (Exception e) {
e.printStackTrace();
}
return rowChange > 0 ? RespObject.respOk() : RespObject.respNo("新增失敗");
}
/**
* Description: 刪除操作
*/
@DeleteMapping(value = "/delUserTableById/{id}", name = "刪除表資料")
@ApiOperation("刪除表資料-介面")
public RespObject addUserTableData(@PathVariable("id") int id) {
int rowChange = 0;
try {
rowChange = userService.deleteusertablebyid(id);
} catch (Exception e) {
e.printStackTrace();
}
return rowChange > 0 ? RespObject.respOk() : RespObject.respNo("該ID無效-刪除失敗");
}
/**
* Description: 修改操作
*/
@PutMapping(value = "/updateUserTableById", name = "修改表資料")
@ApiOperation("修改表資料-介面")
public RespObject updateUserTableData(@RequestBody UserTable userTable) {
int id = userTable.getId();
//判斷-{isPresent存在就返回true}
if (id == 0) {
return RespObject.respNo("修改操作必須傳遞主鍵");
}
int rowChange = 0;
try {
rowChange = userService.updateUserTableById(userTable);
} catch (Exception e) {
e.printStackTrace();
}
return rowChange > 0 ? RespObject.respOk() : RespObject.respNo("修改失敗");
}
}
Service
public interface UserService {
/**
* Description: 無條件查詢
*/
List<UserTable> getUsers();
/**
* Description:條件查詢
*/
UserTable getUserById(int userId);
/**
* Description:分頁查詢
*/
List<UserTable> getUserByLimit(int startIndex, int everyPageSize);
/**
* Description: 新增 返回的結果是影響行數
*/
int insertInToUserTable(UserTable tableObj);
/**
* Description: 修改
*/
int updateUserTableById(UserTable tableObj);
/**
* Description:刪除
*/
int deleteusertablebyid(int id);
/**
* Description:登入
*/
UserTable queryForEntity(LoginUser user);
/**
* Description: 根據Email查詢
*/
UserTable getbyUserEmail(String userEmail);
}
ServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
@Override
public List<UserTable> getUsers() {
return userMapper.getUsers();
}
@Override
public UserTable getUserById(int userId) {
return userMapper.getUserById(userId);
}
@Override
public List<UserTable> getUserByLimit(int startIndex, int everyPageSize) {
return userMapper.getUserByLimit(startIndex, everyPageSize);
}
@Override
public int insertInToUserTable(UserTable tableObj) {
return userMapper.insertInToUserTable(tableObj);
}
@Override
public int updateUserTableById(UserTable tableObj) {
return userMapper.updateUserTableById(tableObj);
}
@Override
public int deleteusertablebyid(int id) {
return userMapper.deleteusertablebyid(id);
}
@Override
public UserTable queryForEntity(LoginUser user) {
String username = user.getUsername();
String password = user.getPassword();
return userMapper.selectByUserNameAndPassword(username, password);
}
@Override
public UserTable getbyUserEmail(String userEmail) {
return userMapper.selectByEmail(userEmail);
}
}
Mapper Interface
@Mapper
public interface UserMapper {
/**
* Description: 無條件查詢
*/
List<UserTable> getUsers();
/**
* Description:條件查詢
*/
UserTable getUserById(@Param("userId") int userId);
/**
* Description:分頁查詢
*/
List<UserTable> getUserByLimit(@Param("startIndex") int startIndex, @Param("everyPageSize") int everyPageSize);
/**
* Description: 新增 返回的結果是影響行數
*/
int insertInToUserTable(UserTable tableObj);
/**
* Description: 修改
*/
int updateUserTableById(UserTable tableObj);
/**
* Description:刪除
*/
int deleteusertablebyid(@Param("id") int id);
UserTable selectByUserNameAndPassword(@Param("username") String username, @Param("password") String password);
UserTable selectByEmail(@Param("userEmail") String userEmail);
}
Mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mapper.UserMapper">
<sql id="tableFields">
id,name ,gender,age,address,qq,email
</sql>
<insert id="insertInToUserTable" parameterType="userTable" useGeneratedKeys="true" keyProperty="id">
insert into user (name ,gender,age,address,qq,email) values (#{name},#{gender},#{age},#{address},#{qq},#{email})
</insert>
<update id="updateUserTableById">
update user
<set>
<if test="name!=null">
name=#{name},
</if>
<if test="gender!=null">
gender=#{gender},
</if>
<if test="age!=null">
age=#{age},
</if>
<if test="address!=null">
address=#{address},
</if>
<if test="qq!=null">
qq=#{qq},
</if>
<if test="email!=null">
email=#{email},
</if>
</set>
where id=#{id}
</update>
<delete id="deleteusertablebyid">
delete from user where id=#{id}
</delete>
<!--全部查詢-->
<select id="getUsers" resultType="userTable">
select
<include refid="tableFields"/>
from user;
</select>
<!--條件查詢-->
<select id="getUserById" resultType="userTable">
select * from user where id=#{userId}
</select>
<!--分頁查詢-->
<select id="getUserByLimit" resultType="com.entity.UserTable">
select * from user limit #{startIndex},#{everyPageSize}
</select>
<select id="selectByUserNameAndPassword" resultType="com.entity.UserTable">
select * from user where name=#{username} and address =#{password}
</select>
<select id="selectByEmail" resultType="com.entity.UserTable">
select * from user where email =#{userEmail}
</select>
</mapper>
整合JWT
自定義需要登入註解:不需要登入註解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedTokenByJWT {
boolean required() default true;
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SkipTokenByJWT {
boolean required() default true;
}
JWT攔截器配合Redis記錄狀態,控制登入訪問
public class AuthenticationInterceptor implements HandlerInterceptor {
/**
* Description: HandlerInterceptor介面主要定義了三個方法
* 1.boolean preHandle ():
* 預處理回撥方法,實現處理器的預處理,第三個引數為響應的處理器,自定義Controller,返回值為true表示繼續流程(如呼叫下一個攔截器或處理器)或者接著執行
* postHandle()和afterCompletion();false表示流程中斷,不會繼續呼叫其他的攔截器或處理器,中斷執行。
* <p>
* 2.void postHandle():
* 後處理回撥方法,實現處理器的後處理(DispatcherServlet進行檢視返回渲染之前進行呼叫),此時我們可以通過modelAndView(模型和檢視物件)對模型資料進行處理或對檢視進行處理,modelAndView也可能為null。
* <p>
* 3.void afterCompletion():
* 整個請求處理完畢回撥方法,該方法也是需要當前對應的Interceptor的preHandle()的返回值為true時才會執行,也就是在DispatcherServlet渲染了對應的檢視之後執行。用於進行資源清理。整個請求處理完畢回撥方法。如效能監控中我們可以在此記錄結束時間並輸出消耗時間,還可以進行一些資源清理,類似於try-catch-finally中的finally,但僅呼叫處理器執行鏈中
*
* @author: GuoTong
* @date: 2021-06-28 15:26:49
* @param:
* @return:
*/
@Autowired
UserService userService;
@Autowired
private RedisTemplate redisTemplate;
/**
* Description: 主要流程:
* <p>
* 1.從 http 請求頭中取出 token,
* 2.判斷是否對映到方法
* 3.檢查是否有SkipTokenByJWT註解註釋,有則跳過認證
* 4.檢查有沒有需要使用者登入的註解NeedTokenByJWT,有則需要取出並驗證
* 5.認證通過則可以訪問,不通過會報相關錯誤資訊
*
* @author: GuoTong
* @date: 2021-06-28 15:27:55
* @param:
* @return:
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
// 從 http 請求頭中取出 token
String token = httpServletRequest.getHeader("token");
// 如果不是對映到方法直接通過
if (!(object instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
//檢查是否有SkipTokenByJWT註釋,有則跳過認證
if (method.isAnnotationPresent(SkipTokenByJWT.class)) {
SkipTokenByJWT SkipTokenByJWT = method.getAnnotation(SkipTokenByJWT.class);
if (SkipTokenByJWT.required()) {
return true;
}
}
//檢查有沒有需要使用者許可權的註解
if (method.isAnnotationPresent(NeedTokenByJWT.class)) {
NeedTokenByJWT NeedTokenByJWT = method.getAnnotation(NeedTokenByJWT.class);
if (NeedTokenByJWT.required()) {
// 執行認證
if (token == null) {
throw new RuntimeException("無token,請重新登入");
}
// 獲取 token 中的 user id
String userEmail;
try {
userEmail = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
throw new MyLoginException("401,請重新登入");
}
UserTable user = userService.getbyUserEmail(userEmail);
if (user == null) {
throw new RuntimeException("使用者不存在,請重新登入");
}
// 驗證 token
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getAddress())).build();
try {
jwtVerifier.verify(token);
//Redis如果存在就判斷token是否一致
String redisToken = (String) redisTemplate.opsForValue().get(user.getEmail());
if (!StringUtils.equals(token, redisToken)) {
throw new RuntimeException("使用者登入狀態已過期");
}
} catch (JWTVerificationException e) {
throw new RuntimeException("未檢測到使用者登入401");
}
return true;
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
}
}
註冊攔截器 、編寫Redis序列化配置
@Configuration
public class webMvcConfig implements WebMvcConfigurer {
/**
* Description: 靜態資源過濾
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//ClassPath:/Static/** 靜態資源釋放
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
//釋放swagger
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
//釋放webjars
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
/**
* Description:新增基於JWT認證的攔截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 攔截所有請求,通過判斷是否有 @SkipTokenByJWT 註解 決定是否需要登入
registry.addInterceptor(getInterceptorByJwt()).addPathPatterns("/**");
}
@Bean
public AuthenticationInterceptor getInterceptorByJwt() {
return new AuthenticationInterceptor();
}
/*解決RedisTemplate往redis存入的資料是二進位制檔案(不管是key還是value都是二進位制檔案),自定義json序列化與反序列化規則*/
/**
* redisTemplate 序列化使用的jdkSerializeable, 儲存二進位制位元組碼, 所以自定義序列化類
*
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用Jackson2JsonRedisSerialize 替換預設序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 設定value的序列化規則和 key的序列化規則
redisTemplate.setKeySerializer(new StringRedisSerializer());
//jackson2JsonRedisSerializer就是JSON序列號規則,
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
自定義異常
public class MyLoginException extends RuntimeException {
public MyLoginException(String message) {
super(message);
}
}
全域性異常處理
@RestControllerAdvice
public class GlobalExceptionHander {
private ObjectMapper objectMapper = new ObjectMapper();
private final int NO_LOGIN_CODE = 401;
@ExceptionHandler(value = Exception.class)
public RespObject exceptionHandler(Exception e) {
e.printStackTrace();
return RespObject.respNo(e.getMessage());
}
@ExceptionHandler(value = MyLoginException.class)
public RespObject MyLoginException(Exception e) {
e.printStackTrace();
String message = e.getMessage();
if (String.valueOf(NO_LOGIN_CODE).equals(message)) {
return RespObject.respOk(NO_LOGIN_CODE, e.getMessage());
}
return RespObject.respNo(e.getMessage());
}
}
編寫整合JWTcontroller
@RestController
public class HelloController {
@Autowired
private UserService userService;
@Autowired
private RedisTemplate redisTemplate;
private final static Map<String, Object> RESP;
static {
RESP = new HashMap<>();
RESP.put("author", "郭童");
RESP.put("since", "JDK1.8");
RESP.put("createTime", "2021-06-28 09:28");
RESP.put("backFrame", "SpringBoot2.5.1");
RESP.put("htmlTemp", "Thymeleaf");
}
@RequestMapping(value = "/hello", name = "web專案測試")
public String gotoHelloWorld() {
return "hello world!";
}
@RequestMapping(value = "/", name = "設定預設訪問頁面")
public ModelAndView gotoIndexPage() {
ModelAndView view = new ModelAndView("index");
view.addObject("initData", RESP);
return view;
}
@SkipTokenByJWT
@PostMapping(value = "/login", name = "登入")
public Object loginUser(@RequestBody LoginUser user) {
UserTable userTable = userService.queryForEntity(user);
if (userTable == null) {
return RespObject.respNo("使用者名稱或者密碼錯誤");
}
String token = user.getToken(userTable);
//快取登入狀態
String emailIsRedisKeyByLife = userTable.getEmail();
String dataRedis = (String) redisTemplate.opsForValue().get(emailIsRedisKeyByLife);
if (StringUtils.isEmpty(dataRedis)) {
redisTemplate.opsForValue().set(emailIsRedisKeyByLife, token);
//設定過期時間; TimeUnit.MILLISECONDS 毫秒:設定預設時間是SECONDS秒:60秒
redisTemplate.expire(emailIsRedisKeyByLife, 60, TimeUnit.MINUTES);
}
return RespObject.respLogin(token, userTable);
}
@GetMapping(value = "/getUserById", name = "根據ID獲取資料")
@NeedTokenByJWT
public RespObject getUserTable(@RequestParam("id") int id) {
UserTable user = userService.getUserById(id);
if (user == null) {
return RespObject.respNo("輸入的ID無效");
}
return RespObject.respOk(user);
}
}
整合HTML首頁
<!DOCTYPE html>
<!--suppress ALL-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:include="/common/common.html">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>首頁</title>
</head>
<body>
<h1 class="text-center">Hello</h1>
<table class="table table-hover indexTable" th:object="${initData}">
<tr class="active">
<td>專案編碼作者</td>
<td th:text="*{author}"></td>
</tr>
<tr class="success">
<td>使用JAVA版本</td>
<td th:text="*{since}"></td>
</tr>
<tr class="warning">
<td>專案建立時間</td>
<td th:text="*{createTime}"></td>
</tr>
<tr class="danger">
<td>後端使用框架</td>
<td th:text="*{backFrame}"></td>
</tr>
<tr class="info">
<td>檢視模板引擎</td>
<td th:text="*{htmlTemp}"></td>
</tr>
</table>
<form class="indexTable" id="formByThisPage" onsubmit="return false">
<div class="form-group">
<label for="exampleInputEmail1">ID:</label>
<input type="text" class="form-control" id="userTableId"
placeholder="請輸入ID">
</div>
<button id="btnByThisA" type="button" class="btn btn-default">查詢</button>
</form>
<table class="table table-hover indexTable">
<tr>
<td>查詢結果</td>
<td>
<textarea class="form-control" rows="3" id="selectText"></textarea>
</td>
</tr>
</table>
<form class="indexTable" id="formByThisPage" th:action="@{/login}" method="post" onsubmit="return false">
<div class="form-group">
<label for="exampleInputEmail1">使用者名稱:</label>
<input type="text" name="username" class="form-control" id="exampleInputEmail1"
placeholder="請輸入使用者名稱">
</div>
<div class="form-group">
<label for="exampleInputPassword1">密碼:</label>
<input type="password" name="password" class="form-control" id="exampleInputPassword1" placeholder="請輸入密碼">
</div>
<button id="btnByThis" type="button" class="btn btn-default">登入</button>
</form>
<script type="text/javascript">
$(function (ev) {
$("#btnByThis").on('click', function () {
window.localStorage.token = undefined;
let sendLoginData = {username: $("#exampleInputEmail1").val(), password: $("#exampleInputPassword1").val()}
$.ajax({
url: "/login",
type: "post",
data: JSON.stringify(sendLoginData),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (resp) {
if (resp.code == 200) {
toastr.success("登入成功!");
window.localStorage.token = resp.token;
} else {
toastr.error(resp.msg);
}
}
});
})
$("#btnByThisA").on('click', function () {
let sendLoginData = $("#userTableId").val();
$.ajax({
url: "/getUserById?id=" + sendLoginData,
type: "get",
beforeSend: function (XMLHttpRequest) {
XMLHttpRequest.setRequestHeader("token", window.localStorage.token);
},
success: function (resp) {
if (resp.code == 200) {
$("#selectText").val(JSON.stringify(resp.data));
toastr.success("查詢成功!!");
} else if (resp.code) {
$("#selectText").val(JSON.stringify(resp.data));
toastr.error(resp.msg);
}
}
});
})
});
</script>
</body>
</html>
實體類
@Data
public class UserTable {
private int id;
private String name;
private String address;
private String gender;
private String qq;
private String email;
private int age;
}
@Data
@Accessors(chain = true)
public class LoginUser {
String Id;
String username;
String password;
/**
* Description: Algorithm.HMAC256():使用HS256生成token,金鑰則是使用者的密碼,唯一金鑰的話可以儲存在服務端。
* withAudience()存入需要儲存在token的資訊,這裡我把使用者getEmail存入token中
* @author: GuoTong
* @date: 2021-06-28 15:19:59
* @param:
* @return:
*/
public String getToken(UserTable user) {
String token = "";
token = JWT.create().withAudience(user.getEmail())
.sign(Algorithm.HMAC256(user.getAddress()));
return token;
}
}