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 官??檔可知
-
Letter Date or Time Component Presentation Examples G
Era designator Text AD
y
Year Year 1996
;96
Y
Week year Year 2009
;09
M
Month in year (context sensitive) Month July
;Jul
;07
L
Month in year (standalone form) Month July
;Jul
;07
w
Week in year Number 27
W
Week in month Number 2
D
Day in year Number 189
d
Day in month Number 10
F
Day of week in month Number 2
E
Day name in week Text Tuesday
;Tue
u
Day number of week (1 = Monday, ..., 7 = Sunday) Number 1
a
Am/pm marker Text PM
H
Hour in day (0-23) Number 0
k
Hour in day (1-24) Number 24
K
Hour in am/pm (0-11) Number 0
h
Hour in am/pm (1-12) Number 12
m
Minute in hour Number 30
s
Second in minute Number 55
S
Millisecond Number 978
z
Time zone General time zone Pacific Standard Time
;PST
;GMT-08:00
Z
Time zone RFC 822 time zone -0800
X
Time zone ISO 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檢驗一下:
沒傳參,返回我們定義的返回信息
正常傳參:
?
?