当前位置: 首页 > news >正文

【SpringBoot】基于MybatisPlus的博客管理系统(1)

1.准备工作

1.1数据库

-- 建表SQL
create database if not exists java_blog_spring charset utf8mb4;use java_blog_spring;
-- 用户表
DROP TABLE IF EXISTS java_blog_spring.user_info;
CREATE TABLE java_blog_spring.user_info(`id` INT NOT NULL AUTO_INCREMENT,`user_name` VARCHAR ( 128 ) NOT NULL,`password` VARCHAR ( 128 ) NOT NULL,`github_url` VARCHAR ( 128 ) NULL,`delete_flag` TINYINT ( 4 ) NULL DEFAULT 0,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY ( id ),UNIQUE INDEX user_name_UNIQUE ( user_name ASC )) ENGINE = INNODB DEFAULT CHARACTER
SET = utf8mb4 COMMENT = '用户表';-- 博客表
drop table if exists java_blog_spring.blog_info;
CREATE TABLE java_blog_spring.blog_info (`id` INT NOT NULL AUTO_INCREMENT,`title` VARCHAR(200) NULL,`content` TEXT NULL,`user_id` INT(11) NULL,`delete_flag` TINYINT(4) NULL DEFAULT 0,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY (id))ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '博客表';-- 新增用户信息
insert into java_blog_spring.user_info (user_name, password,github_url)values("zhangsan","123456","https://gitee.com/bubble-fish666/class-java45");
insert into java_blog_spring.user_info (user_name, password,github_url)values("lisi","123456","https://gitee.com/bubble-fish666/class-java45");insert into java_blog_spring.blog_info (title,content,user_id) values("第一篇博客","111我是博客正文我是博客正文我是博客正文",1);
insert into java_blog_spring.blog_info (title,content,user_id) values("第二篇博客","222我是博客正文我是博客正文我是博客正文",2);

1.2pom文件配置(MybatisPlus依赖)

MybatisPlus依赖:

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.5</version>
</dependency>

1.3yml文件配置(数据库配置)

记得更改password

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/java_blog_spring?characterEncoding=utf8&useSSL=falseusername: rootpassword: '123456'driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:configuration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:file:name: spring-blog.log

1.4项目架构初始化

前期的架构:

 

开发中, 以下命名统称为实体类:

POJO
Model
Entity


在实际开发中, 实体类的划分要细的多:

VO(value object):   表现层对象
DO(Data Object)/PO(Persistant Object): 持久层/数据层对象
DTO(Data Transfer Object): 数据传输对象
BO(Business Object): 业务对象
细分实体类, 可以实现业务代码的解耦.

详情见:实体类

2.业务实现

2.1获取博客列表

1.第一步:实现实体类  对接数据库数据

//do层数据库资源对象
@Data
@AllArgsConstructor
public class BlogInfo {@TableId(type = IdType.AUTO)private Integer id;private String title;private String content;private Integer userId;private Integer deleteFlag;private LocalDateTime createTime;private LocalDateTime updateTime;
}
@Data
public class UserInfo {@TableId(type = IdType.AUTO)private Integer id;private String userName;private String password;private String githubUrl;private Integer deleteFlag;private LocalDateTime createTime;private LocalDateTime updateTime;
}

2.实现返回对象类  对接前端

@Data
public class BlogInfoResponse {@TableId(type = IdType.AUTO)private Integer id;private String title;private String content;//    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime createTime;//重写构造方法public String getCreateTime() {return DateUtils.format(createTime);}//通过重写0content构造方法完成业务想要的返回结果  如:对字符串进行拼接等等}

BlogInfoResponse 是返回前端展示博客列表所需的数据

注意:

我们需要掌握更改日期格式的方法:

常见的日期类型有:Date  LocalDateTime

在这里我们用的是LocalDateTime

那我们就先讲它的转化方法

		LocalDateTime localDateTime = LocalDateTime.now();DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");String format1 = dateTimeFormatter.format(localDateTime);System.out.println(format1);

使用 DateTimeFormatter 类进行格式定义

类型格式的定义是什么呢?

查询java.text.SimpleDateFormat 官⽅⽂档可知

  • LetterDate or Time ComponentPresentationExamples
    GEra designatorTextAD
    yYearYear1996; 96
    YWeek yearYear2009; 09
    MMonth in year (context sensitive)MonthJuly; Jul; 07
    LMonth in year (standalone form)MonthJuly; Jul; 07
    wWeek in yearNumber27
    WWeek in monthNumber2
    DDay in yearNumber189
    dDay in monthNumber10
    FDay of week in monthNumber2
    EDay name in weekTextTuesday; Tue
    uDay number of week (1 = Monday, ..., 7 = Sunday)Number1
    aAm/pm markerTextPM
    HHour in day (0-23)Number0
    kHour in day (1-24)Number24
    KHour in am/pm (0-11)Number0
    hHour in am/pm (1-12)Number12
    mMinute in hourNumber30
    sSecond in minuteNumber55
    SMillisecondNumber978
    zTime zoneGeneral time zonePacific Standard Time; PST; GMT-08:00
    ZTime zoneRFC 822 time zone-0800
    XTime zoneISO 8601 time zone-08; -0800; -08:00

Date的转化方法:

		Date date = new Date();//SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");String format = simpleDateFormat.format(date);System.out.println(format);

 所以我们通过重写构造方法完成日期格式修改

最后我们通过AOP思想完成日期统一修改:

public class DateUtils {public static String format(LocalDateTime localDateTime) {DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(Constant.PATTERN);return dateTimeFormatter.format(localDateTime);}public static String format(LocalDateTime localDateTime, String pattern) {DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);return dateTimeFormatter.format(localDateTime);}
}
/*** 统一返回结果* @param <T>*/
@Data
public class Result<T> {private int code;private String errMsg;private T data;public static <T> Result success(T data) {Result<T> re = new Result<>();re.setCode(ResultCodeEnum.SUCCESS.getCode());re.setData(data);return re;}public static <T> Result fail(String errMsg) {Result<T> re = new Result<>();re.setCode(ResultCodeEnum.FAIL.getCode());re.setErrMsg(errMsg);return re;}public static <T> Result fail(String errMsg, T data) {Result<T> re = new Result<>();re.setCode(ResultCodeEnum.FAIL.getCode());re.setErrMsg(errMsg);re.setData(data);return re;}
}

Result:统一返回结果 

注意:在静态方法中使用T泛型时要在static后加<T>

在这一步我们在使用code时可以选择:

1.在Constant中定义静态常亮

2.定义枚举

我选择使用枚举:

@AllArgsConstructor
public enum ResultCodeEnum {SUCCESS(200),FAIL(-1);@Getterprivate int code;}

 3.Controller  Service  Mapper  三件套

Controller:在注入BlogService 时推荐使用@Resource  因为可能使用实现了多个对象的接口

同时注入的类型为接口类型,方便修改注入(只用修改@Resource name属性)

@Slf4j
@RestController
@RequestMapping("/blog")
public class BlogInfoController {@Resource(name = "blogService")private BlogService blogService;@RequestMapping("/getList")public List<BlogInfoResponse> getList() {log.info("获取博客列表...");return blogService.getList();}
}

 

Service :先定义接口,然后在impl包中实现具体类并处理逻辑

 

@Service
public interface BlogService {List<BlogInfoResponse> getList();
}
@Service("blogService")
public class BlogServiceImpl implements BlogService {@Resourceprivate BlogInfoMapper blogInfoMapper;@Overridepublic List<BlogInfoResponse> getList() {//1.SQL拼接QueryWrapper<BlogInfo> queryWrapper = new QueryWrapper<>();queryWrapper.lambda().eq(BlogInfo::getDeleteFlag, Constant.IS_DELETE);List<BlogInfo> blogInfos = blogInfoMapper.selectList(queryWrapper);//2.将获取的数据转化为BlogInfoResponse用于返回List<BlogInfoResponse> list = blogInfos.stream().map(blogInfo -> {BlogInfoResponse blogInfoResponse = new BlogInfoResponse();//根据属性名称进行复制  原数据  转化数据BeanUtils.copyProperties(blogInfo, blogInfoResponse);return blogInfoResponse;}).collect(Collectors.toList());//转化listreturn list;}}

注意点:

1.在 @Service中进行名称绑定

2.参数转换:

使用blogInfos.stream().map()与lambda表达式实现遍历  (或者使用for循环)

代码中的链式调用解释如下:

blogInfos.stream(): 将 List 转换为一个 stream

blogInfos.stream().map(x -> {转换规则, return y}): 对 List 中的每一个元素根据指定规则进行转换(x: 原来的元素; y: 转换后的元素)

.collect(Collectors.toList()): 将转换后的 Stream 转换为一个新的 List

3.根据属性名称进行复制    原数据      转化数据

BeanUtils.copyProperties(blogInfo, blogInfoResponse);

Mapper:因为使用了MybatisPlus,不用写SQL语句(舒服)

只用实现BaseMapper<T>接口  T为对接数据库的类,会根据该类生成SQL语句

@Mapper
public interface BlogInfoMapper extends BaseMapper<BlogInfo> {
}

使用postman校验一下:

2.2获取博客详情 

前置工作已经做完了,直接写Controller  Service代码就行

Controller :

    @RequestMapping("/getBlogDetail")public BlogDetailResponse getBlogDetail(@NotNull(message = "blogId 不能为空") Integer blogId) {
//        if(blogId == null) {
//            throw new BlogException("用户id不能为空");
//        }log.info("获取博客详情,id:{}",blogId);return blogService.getBlogDetail(blogId);}

@NotNull(message = "blogId 不能为空"):

jakarta.validation完成的参数校验(javax.validation 是Java Bean Validation API的包名)

 如果参数为空了还要爆出异常,这时候启用我们定义的异常与统一异常处理

@Slf4j
@ResponseBody
@ControllerAdvice
public class ExceptionAdvice {@ExceptionHandlerpublic Result exceptionAdvice(Exception e) {log.error("出现异常e:", e);return Result.fail(e.getMessage());}@ExceptionHandlerpublic Result exceptionAdvice(BlogException e) {log.error("出现异常e:", e);return Result.fail(e.getErrMsg());}@ExceptionHandlerpublic Result exceptionAdvice(HandlerMethodValidationException e) {log.error("出现异常e:", e);//获取异常信息
//        List<String> errors = new ArrayList<>();
//        e.getAllErrors().forEach(error -> errors.add(e.getMessage()));return Result.fail("参数校验失败");}
}

在统一异常处理(@ResponseBody@ControllerAdvice@ExceptionHandler)中可以处理自定义异常与常规异常  同时打印日志 

Service:

    @Overridepublic BlogDetailResponse getBlogDetail(Integer blogId) {QueryWrapper<BlogInfo> queryWrapper = new QueryWrapper<>();//根据id与DeleteFlag查询queryWrapper.lambda().eq(BlogInfo::getId, blogId).eq(BlogInfo::getDeleteFlag, Constant.IS_DELETE);BlogInfo blogInfo = blogInfoMapper.selectOne(queryWrapper);BlogDetailResponse blogDetailResponse = new BlogDetailResponse();BeanUtils.copyProperties(blogInfo, blogDetailResponse);return blogDetailResponse;}

老套路查询后转化类型

postman检验一下:

没传参,返回我们定义的返回信息

正常传参:

 

 

相关文章:

  • 【Unity】使用Socket建立客户端和服务端并进行通信的例子
  • 东土科技NewPre系列智能控制器的创新之旅
  • VMware安装 银河麒麟操作系统桌面版 V10 SP1 2403
  • HotSpot的算法细节
  • 集群系统的五大核心挑战与困境解析
  • 4月28号
  • 漏洞复现清单整理-预备梳理,等待补充
  • 多维驱动:负载均衡何以成为现代系统架构的基石
  • 网络爬取需谨慎:警惕迷宫陷阱
  • Ansible安装配置
  • 代发考试战报:4月份 思科认证,华为认证,考试战报分享
  • Twitter 工作原理|架构解析|社交APP逻辑
  • 洛谷题解 | CF1979C Earning on Bets
  • <Revit二次开发> 通过一组模型线构成墙面,并生成墙。Create(Document, IList.Curve., Boolean)
  • 以梦为舟,驶向中医传承新蓝海
  • 宾馆一次性拖鞋很重要,扬州卓韵酒店用品详细介绍其材质与卫生标准
  • Windows 系统下使用 Docker 搭建Redis 集群(6 节点,带密码)
  • (计数)洛谷 P8386 PA2021 Od deski do deski/P10375 AHOI2024 计数 题解
  • Java项目中使用minio存储服务
  • softlockup_panic=1配置方法及区别
  • 五一小长假,带着小狗去上海音乐厅
  • 中国人保一季度业绩“分化”:财险净利增超92%,寿险增收不增利
  • 东风着陆场近日气象条件满足神舟十九号安全返回要求
  • IMF前副总裁朱民捐赠1000万元,在复旦设立青云学子基金
  • 贵州茅台一季度净利268亿元增长11.56%,系列酒营收增近两成
  • 跟着京剧电影游运河,京杭大运河沿线六城举行京剧电影展映