超詳細(xì)講解Java秒殺項(xiàng)目用戶驗(yàn)證模塊的實(shí)現(xiàn)
接著上期內(nèi)容超詳細(xì)講解Java秒殺項(xiàng)目登陸模塊的實(shí)現(xiàn)
一、用戶驗(yàn)證
未登錄的用戶不能進(jìn)入首頁(yè)
根據(jù)上期內(nèi)容,我未登錄也能進(jìn)入首頁(yè):

1、在方法內(nèi)添加請(qǐng)求與反應(yīng)
①、IUserService
package com.example.seckill.service;
import com.example.seckill.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.seckill.util.response.ResponseResult;
import com.example.seckill.vo.UserVo;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* <p>
* 用戶信息表 服務(wù)類
* </p>
*
* @author lv
* @since 2022-03-15
*/
public interface IUserService extends IService<User> {
ResponseResult<?> findByAccount(UserVo userVo, HttpServletRequest request, HttpServletResponse response);
}②、UserServiceImpl

③、UserController
package com.example.seckill.controller;
import com.example.seckill.service.IUserService;
import com.example.seckill.util.response.ResponseResult;
import com.example.seckill.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
/**
* <p>
* 用戶信息表 前端控制器
* </p>
*
* @author lv
* @since 2022-03-15
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private IUserService userService;
// 用戶登錄
@RequestMapping("/login")
public ResponseResult<?> login(@Valid UserVo userVo, HttpServletRequest request, HttpServletResponse response){
// 調(diào)用service的登錄驗(yàn)證
return userService.findByAccount(userVo,request,response);
}
}2、cookie操作的封裝
package com.example.seckill.util;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
@Slf4j
public class CookieUtils {
/**
* @Description: 得到Cookie的值, 不編碼
*/
public static String getCookieValue(HttpServletRequest request, String cookieName) {
return getCookieValue(request, cookieName, false);
}
/**
* @Description: 得到Cookie的值
*/
public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
Cookie[] cookieList = request.getCookies();
if (cookieList == null || cookieName == null) {
return null;
}
String retValue = null;
try {
for (int i = 0; i < cookieList.length; i++) {
if (cookieList[i].getName().equals(cookieName)) {
if (isDecoder) {
retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
} else {
retValue = cookieList[i].getValue();
}
break;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return retValue;
}
/**
* @Description: 得到Cookie的值
*/
public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
Cookie[] cookieList = request.getCookies();
if (cookieList == null || cookieName == null) {
return null;
}
String retValue = null;
try {
for (int i = 0; i < cookieList.length; i++) {
if (cookieList[i].getName().equals(cookieName)) {
retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
break;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return retValue;
}
/**
* @Description: 設(shè)置Cookie的值 不設(shè)置生效時(shí)間默認(rèn)瀏覽器關(guān)閉即失效,也不編碼
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue) {
setCookie(request, response, cookieName, cookieValue, -1);
}
/**
* @Description: 設(shè)置Cookie的值 在指定時(shí)間內(nèi)生效,但不編碼
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage) {
setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);
}
/**
* @Description: 設(shè)置Cookie的值 不設(shè)置生效時(shí)間,但編碼
* 在服務(wù)器被創(chuàng)建,返回給客戶端,并且保存客戶端
* 如果設(shè)置了SETMAXAGE(int seconds),會(huì)把cookie保存在客戶端的硬盤中
* 如果沒(méi)有設(shè)置,會(huì)默認(rèn)把cookie保存在瀏覽器的內(nèi)存中
* 一旦設(shè)置setPath():只能通過(guò)設(shè)置的路徑才能獲取到當(dāng)前的cookie信息
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
String cookieValue, boolean isEncode) {
setCookie(request, response, cookieName, cookieValue, -1, isEncode);
}
/**
* @Description: 設(shè)置Cookie的值 在指定時(shí)間內(nèi)生效, 編碼參數(shù)
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);
}
/**
* @Description: 設(shè)置Cookie的值 在指定時(shí)間內(nèi)生效, 編碼參數(shù)(指定編碼)
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
String cookieValue, int cookieMaxage, String encodeString) {
doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);
}
/**
* @Description: 刪除Cookie帶cookie域名
*/
public static void deleteCookie(HttpServletRequest request, HttpServletResponse response,
String cookieName) {
doSetCookie(request, response, cookieName, null, -1, false);
}
/**
* @Description: 設(shè)置Cookie的值,并使其在指定時(shí)間內(nèi)生效
*/
private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
try {
if (cookieValue == null) {
cookieValue = "";
} else if (isEncode) {
cookieValue = URLEncoder.encode(cookieValue, "utf-8");
}
Cookie cookie = new Cookie(cookieName, cookieValue);
if (cookieMaxage > 0)
cookie.setMaxAge(cookieMaxage);
if (null != request) {// 設(shè)置域名的cookie
String domainName = getDomainName(request);
log.info("========== domainName: {} ==========", domainName);
if (!"localhost".equals(domainName)) {
cookie.setDomain(domainName);
}
}
cookie.setPath("/");
response.addCookie(cookie);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description: 設(shè)置Cookie的值,并使其在指定時(shí)間內(nèi)生效
*/
private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
String cookieName, String cookieValue, int cookieMaxage, String encodeString) {
try {
if (cookieValue == null) {
cookieValue = "";
} else {
cookieValue = URLEncoder.encode(cookieValue, encodeString);
}
Cookie cookie = new Cookie(cookieName, cookieValue);
if (cookieMaxage > 0)
cookie.setMaxAge(cookieMaxage);
if (null != request) {// 設(shè)置域名的cookie
String domainName = getDomainName(request);
log.info("========== domainName: {} ==========", domainName);
if (!"localhost".equals(domainName)) {
cookie.setDomain(domainName);
}
}
cookie.setPath("/");
response.addCookie(cookie);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description: 得到cookie的域名
*/
private static final String getDomainName(HttpServletRequest request) {
String domainName = null;
String serverName = request.getRequestURL().toString();
if (serverName == null || serverName.equals("")) {
domainName = "";
} else {
serverName = serverName.toLowerCase();
serverName = serverName.substring(7);
final int end = serverName.indexOf("/");
serverName = serverName.substring(0, end);
if (serverName.indexOf(":") > 0) {
String[] ary = serverName.split("\\:");
serverName = ary[0];
}
final String[] domains = serverName.split("\\.");
int len = domains.length;
if (len > 3 && !isIp(serverName)) {
// www.xxx.com.cn
domainName = "." + domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
} else if (len <= 3 && len > 1) {
// xxx.com or xxx.cn
domainName = "." + domains[len - 2] + "." + domains[len - 1];
} else {
domainName = serverName;
}
}
return domainName;
}
public static String trimSpaces(String IP) {//去掉IP字符串前后所有的空格
while (IP.startsWith(" ")) {
IP = IP.substring(1, IP.length()).trim();
}
while (IP.endsWith(" ")) {
IP = IP.substring(0, IP.length() - 1).trim();
}
return IP;
}
public static boolean isIp(String IP) {//判斷是否是一個(gè)IP
boolean b = false;
IP = trimSpaces(IP);
if (IP.matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")) {
String s[] = IP.split("\\.");
if (Integer.parseInt(s[0]) < 255)
if (Integer.parseInt(s[1]) < 255)
if (Integer.parseInt(s[2]) < 255)
if (Integer.parseInt(s[3]) < 255)
b = true;
}
return b;
}
}3、UserServiceImpl
// 最初版本(session),但Session內(nèi)數(shù)據(jù)是服務(wù)器共用的
// 所有不讓名字重復(fù)
String ticket=UUID.randomUUID().toString().replace("-","");
request.getSession().setAttribute(ticket,user);
// 將生成的ticket給用戶,用戶如何驗(yàn)證?使用cookie
CookieUtils.setCookie(request,response,"ticket",ticket);點(diǎn)擊登錄時(shí),查看應(yīng)用程序,cookie內(nèi)有值

4、跳轉(zhuǎn)界面PathController
跳轉(zhuǎn)方法:
// 跳所有二級(jí)頁(yè)面
@RequestMapping("/{dir}/{path}")
public String toPath(@PathVariable("dir") String dir, @PathVariable("path") String path, HttpServletRequest request){
String ticket= CookieUtils.getCookieValue(request,"ticket");
if(ticket==null){
throw new BusinessException(ResponseResultCode.TICKET_ERROR);
}
// 去session中取到ticket對(duì)應(yīng)的用戶,判斷是否有值
Object obj=request.getSession().getAttribute(ticket);
if(obj==null){
throw new BusinessException(ResponseResultCode.TICKET_ERROR);
}
return dir+"/"+path;
}未登錄時(shí)訪問(wèn)主界面失?。褐挥械卿洺晒蟛拍茉L問(wèn)

二、全局session
根據(jù)以上操作完后,session仍然有問(wèn)題,,session只能在當(dāng)前某一臺(tái)服務(wù)器中,
需使用第三者完成數(shù)據(jù)共享,此處使用redis方式,將需要緩存的數(shù)據(jù)丟到緩存內(nèi)
1、導(dǎo)入依賴
此處全局session是spring session中的一個(gè),spring session就是spring中的一個(gè)文件
<!--commons-pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--spring-session將session借助于第三方存儲(chǔ)(redis/mongodb等等),默認(rèn)redis-->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>2、配置yml文件redis
spring:
redis:
host: 47.100.191.44
password: xiaoli_redis
database: 0
port: 6379

3、開(kāi)啟虛擬機(jī)
現(xiàn)在開(kāi)啟虛擬機(jī)
三、自定義redis實(shí)現(xiàn)功能
完成全局session的作用
1、新建RedisConfig文件
用于操作redis
package com.example.seckill.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
public RedisTemplate redisTemplate(RedisConnectionFactory factory){
// 新建一個(gè)
RedisTemplate redisTemplate=new RedisTemplate();
//設(shè)置一下使用連接工廠
redisTemplate.setConnectionFactory(factory);
// 額外設(shè)置
// 將key序列化操作,轉(zhuǎn)化為string
redisTemplate.setKeySerializer(new StringRedisSerializer());
// value被轉(zhuǎn)化為json
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
// 額外設(shè)置(hash 就是 map集合)
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
// 讓設(shè)置生效
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}2、實(shí)現(xiàn)全局session
①、寫個(gè)幫助類,用于調(diào)用
IRedisService接口:
package com.example.seckill.service;
import com.example.seckill.pojo.User;
public interface IRedisService {
void putUserByTicket(String ticket, User user);
User getUserByTicket(String ticket);
}實(shí)現(xiàn)接口:
package com.example.seckill.service.impl;
import com.example.seckill.pojo.User;
import com.example.seckill.service.IRedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class RedisServiceImpl implements IRedisService {
@Autowired
private RedisTemplate redisTemplate;
@Override
public void putUserByTicket(String ticket, User user) {
redisTemplate.opsForValue().set("user:"+ticket,user,2L, TimeUnit.HOURS);
}
@Override
public User getUserByTicket(String ticket) {
Object obj=redisTemplate.opsForValue().get("user:"+ticket);
if(obj==null || !(obj instanceof User)){
return null;
}
return (User)obj;
}
}②、redisService到緩存中拿元素
@Autowired
private IRedisService redisService;
// 跳所有二級(jí)頁(yè)面
@RequestMapping("/{dir}/{path}")
public String toPath(@PathVariable("dir") String dir, @PathVariable("path") String path, HttpServletRequest request){
// 獲取用戶的ticket
String ticket= CookieUtils.getCookieValue(request,"ticket");
if(ticket==null){
throw new BusinessException(ResponseResultCode.TICKET_ERROR);
}
// 去session中取到ticket對(duì)應(yīng)的用戶,判斷是否有值
// Object obj=request.getSession().getAttribute(ticket);
// 去緩存中拿元素
User user=redisService.getUserByTicket(ticket);
if(user==null){
throw new BusinessException(ResponseResultCode.TICKET_ERROR);
}
return dir+"/"+path;
}③、放到緩存中
UserServiceImpl:
// 放到緩存中去
redisService.putUserByTicket(ticket,user);
package com.example.seckill.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.seckill.exception.BusinessException;
import com.example.seckill.pojo.User;
import com.example.seckill.mapper.UserMapper;
import com.example.seckill.service.IRedisService;
import com.example.seckill.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.seckill.util.CookieUtils;
import com.example.seckill.util.MD5Utils;
import com.example.seckill.util.ValidatorUtils;
import com.example.seckill.util.response.ResponseResult;
import com.example.seckill.util.response.ResponseResultCode;
import com.example.seckill.vo.UserVo;
import com.sun.deploy.nativesandbox.comm.Request;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.websocket.Session;
import java.util.Date;
import java.util.UUID;
/**
* <p>
* 用戶信息表 服務(wù)實(shí)現(xiàn)類
* </p>
*
* @author lv
* @since 2022-03-15
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Autowired
private IRedisService redisService;
@Override
public ResponseResult<?> findByAccount(UserVo userVo, HttpServletRequest request, HttpServletResponse response) {
// 先判斷信息是否符合(賬號(hào)是否是手機(jī)號(hào)碼,密碼是不是空)
// if(!ValidatorUtils.isMobile(userVo.getMobile())){
// throw new BusinessException(ResponseResultCode.USER_ACCOUNT_NOT_MOBLIE);
// }
// if(StringUtils.isBlank(userVo.getPassword())){
// throw new BusinessException(ResponseResultCode.USER_PASSWORD_NOT_MATCH);
// }
// 再去數(shù)據(jù)庫(kù)查出對(duì)應(yīng)的用戶(mobile)
User user=this.getOne(new QueryWrapper<User>().eq("id",userVo.getMobile()));
if(user==null){
throw new BusinessException(ResponseResultCode.USER_ACCOUNT_NOT_FIND);
}
// 比較密碼
// 二重加密(前端->后端,后端->數(shù)據(jù)庫(kù))
String salt=user.getSalt();
// 將前臺(tái)的加密密碼和后端的鹽再次進(jìn)行加密
String newPassword=MD5Utils.formPassToDbPass(userVo.getPassword(),salt);
if(!newPassword.equals(user.getPassword())){
throw new BusinessException(ResponseResultCode.USER_PASSWORD_NOT_MATCH);
}
// 修改最后的登錄時(shí)間
this.update(new UpdateWrapper<User>().eq("id",userVo.getMobile()).set("last_login_date",new Date()).setSql("login_count=login_count+1"));
// 最初版本(session),但Session內(nèi)數(shù)據(jù)是服務(wù)器共用的
// 所有不讓名字重復(fù)
String ticket=UUID.randomUUID().toString().replace("-","");
// 放到全局或者當(dāng)服務(wù)器的session
// request.getSession().setAttribute(ticket,user);
// 放到緩存中去
redisService.putUserByTicket(ticket,user);
// 將生成的ticket給用戶,用戶如何驗(yàn)證?使用cookie
CookieUtils.setCookie(request,response,"ticket",ticket);
return ResponseResult.success();
}
}④、LocalDateTime無(wú)法構(gòu)造實(shí)例
![]()
LocalDateTime是Java8推薦使用的時(shí)間類,我此處無(wú)法轉(zhuǎn)化,需要去配置解析器,我就改變實(shí)體類中的LocalDateTime改為時(shí)間戳Timestamp


四、使用參數(shù)解析器
在controller類中方法內(nèi)加上User實(shí)體類參數(shù),查詢出用戶,自動(dòng)將信息賦值
1、新建WebConfig文件
package com.example.seckill.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
@Configuration
//打開(kāi)mvc的功能
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Autowired
private UserArgumentResolvers userArgumentResolvers;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(userArgumentResolvers);
}
// 使靜態(tài)資源仍然可使用
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//靜態(tài)資源訪問(wèn)映射 映射路徑 -> 本地資源路徑
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/");
}
}2、定義參數(shù)解析器
UserArgumentResolvers :
package com.example.seckill.config;
import com.example.seckill.exception.BusinessException;
import com.example.seckill.pojo.User;
import com.example.seckill.service.IRedisService;
import com.example.seckill.util.CookieUtils;
import com.example.seckill.util.response.ResponseResultCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpServletRequest;
@Component
public class UserArgumentResolvers implements HandlerMethodArgumentResolver {
@Autowired
private IRedisService redisService;
// supportsParameter方法判斷參數(shù)是否需要解析,決定了resolveArgument方法是否運(yùn)行
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getParameterType() == User.class;
}
// 解析參數(shù)
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
// 參數(shù)解析User,因?yàn)楹芏嗟胤叫枰龅卿涷?yàn)證
HttpServletRequest request=(HttpServletRequest) nativeWebRequest.getNativeRequest();
// 獲取用戶的ticket
String ticket= CookieUtils.getCookieValue(request,"ticket");
if(ticket==null){
throw new BusinessException(ResponseResultCode.TICKET_ERROR);
}
// 去session中取到ticket對(duì)應(yīng)的用戶,判斷是否有值
// Object obj=request.getSession().getAttribute(ticket);
// 去緩存中拿元素
User user=redisService.getUserByTicket(ticket);
if(user==null){
throw new BusinessException(ResponseResultCode.TICKET_ERROR);
}
return user;//經(jīng)過(guò)了參數(shù)解析后,參數(shù)會(huì)變成你這個(gè)地方返回的值
}
}3、PathController
package com.example.seckill.controller;
import com.example.seckill.exception.BusinessException;
import com.example.seckill.pojo.User;
import com.example.seckill.service.IRedisService;
import com.example.seckill.util.CookieUtils;
import com.example.seckill.util.response.ResponseResultCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
public class PathController {
// 登錄跳首頁(yè)
@RequestMapping("/")
public String toPath(){
return "login";
}
// 跳所有二級(jí)頁(yè)面
@RequestMapping("/{dir}/{path}")
public String toPath(@PathVariable("dir") String dir, @PathVariable("path") String path, User user){
return dir+"/"+path;
}
}4、訪問(wèn)主界面得到相關(guān)信息:

本期內(nèi)容結(jié)束~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
到此這篇關(guān)于超詳細(xì)講解Java秒殺項(xiàng)目用戶驗(yàn)證模塊的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java 用戶驗(yàn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot實(shí)現(xiàn)PDF添加水印的三種方法
本文主要介紹了SpringBoot實(shí)現(xiàn)PDF添加水印的三種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
SpringBoot整合Security實(shí)現(xiàn)權(quán)限控制框架(案例詳解)
Spring Security是一個(gè)能夠?yàn)榛赟pring的企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪問(wèn)控制解決方案的安全框,是一個(gè)重量級(jí)的安全管理框架,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-08-08
java實(shí)現(xiàn)簡(jiǎn)單三子棋游戲
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單三子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
Java并行執(zhí)行任務(wù)的幾種方案小結(jié)
這篇文章主要介紹了Java并行執(zhí)行任務(wù)的幾種方案小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
Javaweb mybatis接口開(kāi)發(fā)實(shí)現(xiàn)過(guò)程詳解
這篇文章主要介紹了Javaweb mybatis接口開(kāi)發(fā)實(shí)現(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
@Autowired注解注入的xxxMapper報(bào)錯(cuò)問(wèn)題及解決
這篇文章主要介紹了@Autowired注解注入的xxxMapper報(bào)錯(cuò)問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
將Swagger2文檔導(dǎo)出為HTML或markdown等格式離線閱讀解析
這篇文章主要介紹了將Swagger2文檔導(dǎo)出為HTML或markdown等格式離線閱讀,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-11-11
mybatis查詢結(jié)果返回至實(shí)體類的示例代碼
這篇文章主要介紹了mybatis查詢結(jié)果返回至實(shí)體類的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07

