https://www.wolai.com/v5Kuct5ZtPeVBk4NBUGBWF
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- 数据库相关配置启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- druid启动器的依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.18</version>
</dependency>
<!-- 驱动类-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
<!-- SpringBoot应用打包插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
application.yml
# server配置
server:
port: 8080
servlet:
context-path: /
# 连接池配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
url: jdbc:mysql:///sm_db
username: root
password: pj123456
driver-class-name: com.mysql.cj.jdbc.Driver
# mybatis-plus的配置
mybatis-plus:
type-aliases-package: com.melon.pojo
global-config:
db-config:
logic-delete-field: isDeleted #全局逻辑删除
id-type: auto #主键策略自增长
table-prefix: news_ # 设置表的前缀
#jwt配置
jwt:
token:
tokenExpiration: 120 #有效时间,单位分钟
tokenSignKey: headline123456 #当前程序签名秘钥 自定义
package com.melon;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@MapperScan("com.melon.mapper")
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class,args);
}
//配置mybatis-plus插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); //分页
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); //乐观锁
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); //防全局修改和删除
return interceptor;
}
}
package com.melon.utils;
/**
* 全局统一返回结果类
*/
public class Result<T> {
// 返回码
private Integer code;
// 返回消息
private String message;
// 返回数据
private T data;
public Result(){}
// 返回数据
protected static <T> Result<T> build(T data) {
Result<T> result = new Result<T>();
if (data != null)
result.setData(data);
return result;
}
public static <T> Result<T> build(T body, Integer code, String message) {
Result<T> result = build(body);
result.setCode(code);
result.setMessage(message);
return result;
}
public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
Result<T> result = build(body);
result.setCode(resultCodeEnum.getCode());
result.setMessage(resultCodeEnum.getMessage());
return result;
}
/**
* 操作成功
* @param data baseCategory1List
* @param <T>
* @return
*/
public static<T> Result<T> ok(T data){
Result<T> result = build(data);
return build(data, ResultCodeEnum.SUCCESS);
}
public Result<T> message(String msg){
this.setMessage(msg);
return this;
}
public Result<T> code(Integer code){
this.setCode(code);
return this;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
package com.melon.utils;
/**
* 统一返回结果状态信息类
*
*/
public enum ResultCodeEnum {
SUCCESS(200,"success"),
USERNAME_ERROR(501,"usernameError"),
PASSWORD_ERROR(503,"passwordError"),
NOTLOGIN(504,"notLogin"),
USERNAME_USED(505,"userNameUsed");
private Integer code;
private String message;
private ResultCodeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
package com.melon.utils;
import org.springframework.stereotype.Component;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@Component
public final class MD5Util {
public static String encrypt(String strSrc) {
try {
char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f' };
byte[] bytes = strSrc.getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes);
bytes = md.digest();
int j = bytes.length;
char[] chars = new char[j * 2];
int k = 0;
for (int i = 0; i < bytes.length; i++) {
byte b = bytes[i];
chars[k++] = hexChars[b >>> 4 & 0xf];
chars[k++] = hexChars[b & 0xf];
}
return new String(chars);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("MD5加密出错!!+" + e);
}
}
}
#jwt配置
jwt:
token:
tokenExpiration: 120 #有效时间,单位分钟
tokenSignKey: headline123456 #当前程序签名秘钥 自定义
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
package com.melon.utils;
import com.alibaba.druid.util.StringUtils;
import io.jsonwebtoken.*;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
@Data
@Component
@ConfigurationProperties(prefix = "jwt.token")
public class JwtHelper {
private long tokenExpiration; //有效时间,单位毫秒 1000毫秒 == 1秒
private String tokenSignKey; //当前程序签名秘钥
//生成token字符串
public String createToken(Long userId) {
System.out.println("tokenExpiration = " + tokenExpiration);
System.out.println("tokenSignKey = " + tokenSignKey);
String token = Jwts.builder()
.setSubject("YYGH-USER")
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration*1000*60)) //单位分钟
.claim("userId", userId)
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}
//从token字符串获取userid
public Long getUserId(String token) {
if(StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer)claims.get("userId");
return userId.longValue();
}
//判断token是否有效
public boolean isExpiration(String token){
try {
boolean isExpire = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token)
.getBody()
.getExpiration().before(new Date());
//没有过期,有效,返回false
return isExpire;
}catch(Exception e) {
//过期出现异常,返回true
return true;
}
}
}
1.controller
@PostMapping("login")
public Result login(@RequestBody User user){
Result result = userService.login(user);
return result;
}
2.service
// 登陆
Result login(User user);
3.serviceimpl
public Result login(User user) {
// 根据账号查询
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getUsername,user.getUsername());
User loginUser = userMapper.selectOne(queryWrapper);
// 账号判断
if(loginUser == null){
// 账号错误
return Result.build(null, ResultCodeEnum.USERNAME_ERROR);
}
// 密码判断
if(!StringUtils.isEmpty(user.getUserPwd())
&& loginUser.getUserPwd().equals(MD5Util.encrypt(user.getUserPwd())))
{
// 账号密码正确
// 根据用户唯一标识生成token
String token = jwtHelper.createToken(Long.valueOf(loginUser.getUid()));
HashMap data = new HashMap();
data.put("token",token);
return Result.ok(data);
}
// 密码错误
return Result.build(null,ResultCodeEnum.PASSWORD_ERROR);
}
大致流程:
1.获取token,解析token对应的userId
2.根据userId,查询用户数据
3.将用户数据的密码置空,并且把用户数据封装到结果中key = loginUser
4.失败返回504 (本次先写到当前业务,后期提取到和全局异常处理器)
1.controller
@GetMapping("getUserInfo")
public Result userInfo(@RequestHeader String token){
Result result = userService.getUserInfo(token);
return result;
}
2.service
// 查询用户信息
Result getUserInfo(String token);
3.serviceimpl
public Result getUserInfo(String token) {
// 判定是否有效期
if(jwtHelper.isExpiration(token)){
//true过期,直接返回登陆
return Result.build(null,ResultCodeEnum.NOTLOGIN);
}
// 根据token获取用户对应的uid
int userId = jwtHelper.getUserId(token).intValue();
// 查询数据
User user = userMapper.selectById(userId);
if(user != null){
user.setUserPwd(null);
Map data = new HashMap();
data.put("loginUser",user);
return Result.ok(data);
}
return Result.build(null,ResultCodeEnum.PASSWORD_ERROR);
}
问题:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.melon.mapper.UserMapper.selectById
解决:
没有在对应的实体类主键上加@Tableid
@Data
public class User implements Serializable {
@TableId
private Integer uid;
1.controller
@PostMapping("checkUserName")
public Result checkUserName(String username){
Result result = userService.checkUserName(username);
return result;
}
2.service
// 用户注册
Result regist(User user);
3.serviceimple
public Result checkUserName(String username) {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getUsername,username);
Long count = userMapper.selectCount(queryWrapper);
if (count==0) {
return Result.ok(null);
}
return Result.build(null,ResultCodeEnum.USERNAME_USED);
}
@PostMapping("regist")
public Result regist(@RequestBody User user){
Result result = userService.regist(user);
return result;
}
// 用户注册
Result regist(User user);
public Result regist(User user) {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getUsername,user.getUsername());
Long count = userMapper.selectCount(queryWrapper);
if (count>0) {
return Result.build(null,ResultCodeEnum.USERNAME_USED);
}
user.setUserPwd(MD5Util.encrypt(user.getUserPwd()));
userMapper.insert(user);
return Result.ok(null);
}
@GetMapping("findAllTypes")
public Result findAllTypes(){
Result result = typeService.findAllTypes();
return result;
}
public Result findAllTypes() {
List<Type> types = typeMapper.selectList(null);
return Result.ok(types);
}
1.controller
@PostMapping("findNewsPage")
public Result findNewsPage(@RequestBody PortalVo portalVo){
Result result = headlineService.findNewsPage(portalVo);
return result;
}
2.service
// 首页数据查询
Result findNewsPage(PortalVo portalVo);
3.serviceImpl
public Result findNewsPage(PortalVo portalVo) {
// Page -> 当前页面,页容量
IPage<Map> page = new Page<>(portalVo.getPageNum(),portalVo.getPageSize());
headlineMapper.selectPage(page,portalVo);
List<Map> records = page.getRecords();
Map data = new HashMap();
// Map<Object, Object> data = new HashMap<>();
data.put("pageData",records);
data.put("pageNum",page.getCurrent());
data.put("pageSize",page.getSize());
data.put("totalPage",page.getPages());
data.put("totalSize",page.getTotal());
Map pageInfo = new HashMap();
pageInfo.put("pageInfo",data);
return Result.ok(pageInfo);
}
4.mapper
IPage<Map> selectPage(IPage iPage, @Param("portalVo") PortalVo portalVo);
5.mapper.xml
<select id="selectPage" resultType="map">
select hid,title,type,page_views pageViews,TIMESTAMPDIFF(HOUR,create_time,NOW()) pastHours,
publisher from news_headline where is_deleted=0
<if test="portalVo.keyWords !=null and portalVo.keyWords.length()>0 ">
and title like concat('%',#{portalVo.keyWords},'%')
</if>
<if test="portalVo.type != null and portalVo.type != 0">
and type = #{portalVo.type}
</if>
</select>
@PostMapping("showHeadlineDetail")
public Result showHeadlineDetail(Integer hid){
Result result = headlineService.showHeadlineDetail(hid);
return result;
}
// 查询详情信息
Result showHeadlineDetail(Integer hid);
public Result showHeadlineDetail(Integer hid) {
Map data = headlineMapper.queryDetail(hid);
Map headlineMap = new HashMap();
headlineMap.put("headline",data);
// 修改阅读量+1
Headline headline = new Headline();
headline.setHid((Integer) data.get("hid"));
headline.setVersion((Integer) data.get("version"));
// 阅读量+1
headline.setPageViews((Integer) data.get("pageViews")+1);
headlineMapper.updateById(headline);
return Result.ok(headlineMap);
}
Map queryDetail(Integer hid);
<!-- Map queryDetail(Integer hid); -->
<select id="queryDetail" resultType="map">
select hid,title,article,type, h.version ,tname typeName ,page_views pageViews
,TIMESTAMPDIFF(HOUR,create_time,NOW()) pastHours,publisher
,nick_name author from news_headline h
left join news_type t on h.type = t.tid
left join news_user u on h.publisher = u.uid
where hid = #{hid}
</select>
@GetMapping("checkLogin")
public Result checkLogin(@RequestHeader String token){
boolean expiration = jwtHelper.isExpiration(token);
if(expiration){
return Result.build(null, ResultCodeEnum.NOTLOGIN);
}
return Result.ok(null);
}
这是一个实现了HandlerInterceptor接口的组件,用于在控制器处理请求之前进行预处理。它主要完成以下任务:
1. **获取Token:** 从HTTP请求的头部**token**字段中获取JWT token。
2. **检查Token有效性:** 使用注入的**JwtHelper**组件调用**isExpiration**方法来检查token是否已经过期。注意,如果**isExpiration**方法的意义是“是否过期”,那么方法名可能会让人困惑,更好的命名可能是**isExpired**。
3. **处理验证结果:**
- **Token有效:** 如果token未过期(**expiration**为**false**),则方法返回**true**,允许请求继续执行。
- **Token无效:** 如果token已过期或无效(**expiration**为**true**),则拒绝进一步处理请求,并向客户端返回一个状态码为504的JSON响应,表示用户未登录或认证过期。使用**ObjectMapper**将错误信息序列化为JSON格式,并通过**response.getWriter().print(json);**发送到客户端。
@Component
public class LoginProtectInterceptor implements HandlerInterceptor {
@Autowired
private JwtHelper jwtHelper;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 从请求头中获取token
String token = request.getHeader("token");
// 检查是否有效
boolean expiration = jwtHelper.isExpiration(token);
// 有效放行
if(!expiration){
// 放行
return true;
}
// 状态无效返回504的JSON
Result result = Result.build(null, ResultCodeEnum.NOTLOGIN);
// 序列化为JSON格式
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(result);
// 发送响应给客户端
response.getWriter().print(json);
return false;
}
}
@Configuration
public class WebMVCConfig implements WebMvcConfigurer {
@Autowired
private LoginProtectInterceptor loginProtectInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginProtectInterceptor).addPathPatterns("/headline/**");
}
}
@PostMapping("publish")
public Result publish(@RequestBody Headline headline,@RequestHeader String token){
Result result = headlineService.publish(headline,token);
return result;
}
2.serviceImpl
public Result publish(Headline headline, String token) {
// 根据token查询用户id
int userId = jwtHelper.getUserId(token).intValue();
System.out.println(userId);
// 数据装配
headline.setPublisher(userId);
headline.setPageViews(0);
headline.setCreateTime(new Date());
headline.setUpdateTime(new Date());
headlineMapper.insert(headline);
return Result.ok(null);
}
@PostMapping("findHeadlineByHid")
public Result findHeadlineByHid(Integer hid){
Headline headline = headlineService.getById(hid);
Map data = new HashMap();
data.put("headline",headline);
return Result.ok(data);
}
@PostMapping("update")
public Result update(@RequestBody Headline headline){
Result result = headlineService.updateData(headline);
return result;
}
public Result updateData(Headline headline) {
Integer version = headlineMapper.selectById(headline).getVersion();
headline.setVersion(version); // 乐观锁
headline.setUpdateTime(new Date());
headlineMapper.updateById(headline);
return Result.ok(null);
}
@PostMapping("removeByHid")
public Result removeByHid(Integer hid){
headlineService.removeById(hid);
return Result.ok(null);
}
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- aiwanbo.com 版权所有 赣ICP备2024042808号-3
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务