SpringBoot實戰1
一、開發環境,環境搭建-----創建項目
通過傳統的Maven工程進行創建SpringBoot項目
(1)導入SpringBoot項目開發所需要的依賴
一個父依賴:(工件ID為:spring-boot-starter-parent
)
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.4</version>
</parent>
開發相關依賴
Web依賴:spring-boot-starter-web
<!--引入Web的依賴--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
Mybatis依賴:mybatis-spring-boot-starter
<!--引入Mybatis的依賴--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.4</version></dependency>
MySQL的驅動依賴:mysql-connector-j
<!--引入MySQL的驅動依賴--><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId></dependency>
lombok工具依賴:
<!--lombok依賴--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency>
(2)創建基本的項目架構
Controller,Service,Mapper,POJO,utils
(3)在resources目錄下加入application.yml的SpringBoot項目配置文件,在其中加入Jdbc的相關配置
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/big_event?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTCusername: rootpassword: ****
(4)完成SQL配置,連接數據庫,同時創建數據庫表
(5)添加SpringBoot的啟動類:(項目名)XxxApplication
加上@SpringBootApplication
注解確定為啟動類
@SpringBootApplication
public class BigEventApplication
{public static void main( String[] args) {SpringApplication.run(BigEventApplication.class, args);}
}
二、注冊功能實現
localhost:8080/user/register
Controller層加上@RestController—>@ResponseBody可以自動將返回值轉為JSON格式
通過Post的方式提交數據
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@PostMapping("/register")public Result register(String username, String password){// TODO: 查詢用戶是否存在User user=userService.findByUserName(username);if (user!=null){return Result.error("用戶已存在");}else {// TODO: 用戶不存在的話就開始注冊用戶userService.register(username,password);return Result.success();}}
}
編寫對應的業務層 ,數據層的操作
public interface UserService {// 注冊void register(String username, String password) ;// 根據用戶名查詢用戶User findByUserName(String username);
}
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Overridepublic void register(String username, String password) {// TODO: 對于用于的密碼進行MD5加密處理String md5Password = Md5Util.getMD5String(password);userMapper.add(username,md5Password);}@Overridepublic User findByUserName(String username) {User user =userMapper.findByUserName(username);return user;}
}
@Mapper
public interface UserMapper {// TODO: 必須加入創建時間,更新時間通過sql自帶的now()函數@Insert("insert into user(username,password,create_time,update_time)" +" values(#{username},#{password},now(),now())")void add(String username, String password);@Select("select * from user where username=#{username}")User findByUserName(String username);
}
參數校驗框架(Spring Validation)
在注冊的時候注意加上:對注冊接口的參數進行合法性校驗
使用步驟:
1、引入對應的依賴:spring-boot-starter-validation
<!-- 添加validation依賴用于參數的校驗 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2、在參數前面加上@Pattern注解(@Pattern(regexp=“正則表達式(注意Java中單斜杠不行需轉成\\)”))
public Result register(@Pattern(regexp = "^\\S{5,16}$") String username,@Pattern(regexp = "^\\S{5,16}$") String password)
3、在對應的Controller類上加上@Validated
@Validated
public class UserController
注意:如果遇到參數校驗失敗的情況的話
4、通過全局異常處理器中處理參數校驗失敗
@RestControllerAdvice//表示該類是一個全局異常處理類
@ExceptionHandler(Exception.class)//表示該方法可以處理所有異常
// TODO: 全局異常處理
@RestControllerAdvice
public class GlobalExceptionHandler {// TODO: 捕獲所有異常@ExceptionHandler(Exception.class)public Result handleException(Exception e) {e.printStackTrace();return Result.error(StringUtils.hasLength(e.getMessage())?e.getMessage():"參數校驗失敗");}
}
三、登錄功能實現
1、在數據表中查詢用戶
2、判斷查詢到的用戶是否存在
3、用戶存在判斷密碼是否正確
//TODO: 登錄
@PostMapping("/login")
public Result login(@Pattern(regexp = "^\\S{5,16}$") String username,@Pattern(regexp = "^\\S{5,16}$") String password) {// TODO: 查詢用戶是否存在User loginUser = userService.findByUserName(username);// TODO: 判斷用戶是否存在if(loginUser==null){return Result.error("用戶不存在");}// TODO: 判斷密碼是否正確else{if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){// 登錄成功return Result.success("jwt token令牌");}else {return Result.error("密碼錯誤");}}
}
登錄認證:
通過令牌技術承載業務的數據,減少后續請求
查詢數據庫的次數,1、防止篡改
,2、保證信息的合法性和有效性
JWT令牌:JSON Web Token(通信雙方通過JSON數據格式安全的傳輸信息)
JWT組成—通過Base64的編碼格式進行編碼
1、Header頭部:記錄令牌的類型,簽名算法(用于加密算法)
2、Payload有效載荷:攜帶一些自定義的信息,默認信息–不能存放私密數據
3、Signature簽名:防止Token被篡改,確保安全性
JWT-生成:
引入JWT的依賴
<!-- 添加JWT依賴 -->
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version>
</dependency>
在單元測試中生成jwt令牌
public class JwtTest {@Testpublic void testGen(){Map<String, Object> claims =new HashMap<>();claims.put("id",1);claims.put("username","admin");//生成jwt代碼String token = JWT.create().withClaim("user", claims)//添加自定義信息(載荷).withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))//設置過期時間為12小時.sign(Algorithm.HMAC256("geshihua"));//指定算法,配置密鑰System.out.println(token);}
}
jwt令牌的驗證:
注意:
1、校驗jwt的簽名密鑰要和生成jwt令牌的簽名密鑰吻合
2、jwt令牌解析驗證報錯的話那么說明對應的jwt令牌被篡改了,或者生成的jwt令牌過期失效了
//TODO:jwt令牌的驗證
@Test
public void testParse(){//定義一個字符串模擬用戶傳遞過來的TokenString token ="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" +".eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6ImFkbWluIn0sImV4cCI6MTc0NDMyMTkyNX0" +".wfaRNJPOvVz6sU7rsyxnyzSKdezmhyhwslp4eUW2O4g";//調用API驗證TokenJWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("geshihua")).build();//解析Token,生成一個解析后的jwt對象DecodedJWT decodedJWT = jwtVerifier.verify(token);Map<String, Claim> claims = decodedJWT.getClaims();System.out.println(claims.get("user"));
}
將JWT令牌納入登錄驗證中(登錄成功了之后將相關的信息存儲到Token中
// 登錄成功
Map<String,Object> claims=new HashMap<>();
claims.put("id",loginUser.getId());
claims.put("username",loginUser.getUsername());
String token = JwtUtil.genToken(claims);
return Result.success(token);
在其他的業務接口中解析驗證Token–原理
@GetMapping("/list")
public Result list(@RequestHeader(name = "Authorization") String token, HttpServletResponse response) {//驗證Tokentry {Map<String, Object> claims = JwtUtil.parseToken(token);} catch (Exception e) {response.setStatus(401);return Result.error("請先登錄");}return Result.success("獲取到對應的文章信息了!!!");
}
通過攔截器Interceptor(多個接口都需要同樣的操作可以用攔截器進行實現)
完成對應的驗證操作,只有通過驗證的才可以進行相關的業務操作
1、先創建一個登錄校驗的攔截器(LoginInterceptor)–》需要在攔截器這個類上面加一個注解@Component(用于Bean對象注冊)
攔截器實現HanderInterceptor
接口==>實現preHandle
方法(意味在請求的Controller方法(請求訪問服務器)之前進行調用)
@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//在這個攔截器中驗證Token---》通過請求頭中攜帶的的tokenString token = request.getHeader("Authorization");//解析Tokentry {Map<String, Object> claims = JwtUtil.parseToken(token);//TODO:如果解析成功,則放行return true;} catch (Exception e) {response.setStatus(401);//TODO:如果解析失敗,則返回錯誤信息,并且攔截return false;}}
}
2、添加Interceptor攔截器到WebMvcConfig配置類中–》配置類需要通過注解@Component將配置類注冊到Spring的IOC容器中去
(1)WebMvcConfig配置類需要實現WebMvcConfigurer接口
(2)配置類中將登錄攔截器的Bean自動注入進來
@Autowired
private LoginInterceptor loginInterceptor;
(3)實現對應的接口方法–》用于添加對應的登錄攔截器addInterceptors
@Configuration//TODO:配置類也需要注冊到spring的IOC容器中
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;//TODO:用于攔截器注冊public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor)//TODO: 放行登錄和注冊接口,不進行攔截.excludePathPatterns("/user/login","/user/register");}
}
三、獲取用戶的詳細信息(在進行此業務請求的時候需要再請求頭中攜帶對象的token信息—Authorization)
根據用戶名查詢數據表中的用戶信息(用戶名的信息通過請求頭中的token----Authorization獲取得到)
@RequestHeader(name = "Authorization")String token
通過上面的 參數得到token攜帶的信息–》用戶名的username,id
// TODO: 獲取用戶詳細信息
@GetMapping("/userInfo")
public Result<User> userInfo(@RequestHeader(name = "Authorization")String token){//根據用戶名查詢用戶信息---》用戶名是通過token解析出來的Map<String, Object> map = JwtUtil.parseToken(token);String username = (String) map.get("username");User user = userService.findByUserName(username);return Result.success(user);
}
注意:對于數據表中存在有下劃線的字段的時候在進行查詢的時候不會自動轉化為對應的駝峰命名導致查詢不到對應的信息
解決方式一:
在配置文件中開啟駝峰映射
mybatis:configuration:map-underscore-to-camel-case: true # 開啟下劃線轉駝峰命名 自動將數據表中有下劃線字段的轉換為駝峰明明形式的
解決方式二:
在寫SQL語句的時候對于有下劃線的字段采取起別名的方式:
@Select("select id, username, password, nickname, email, user_pic as userPic, create_time as createTime, update_time as updateTime from user where username=#{username}")