不知道各位小伙伴拿到自己的第一个实战项目的心情是如何的?是兴奋,是紧张,还是茫然?
如上图所示,为此篇文章的核心思想的体现!这是“同事”+“同学”+“自己”在项目中的所思所学所得。
此次的内容我将在我之前的文章SpringBoot_实现基本增删改查(前后端分离版)基础之上将自己的相关理解写得更加透彻一些,因为8月份我刚接触这个框架,很多还是混淆的状态,只知道要这样做,但是不知道为什么要这样做,这此我就来讲讲为什么要这样做。
思想归思想,思想流程是如上图这样,但是具体的编码过程应当按以下的步骤来梳理,逻辑才会更加的清晰易懂!
(1)建立实体类;
(2)Service接口;
(3)XML文件;
(4)Mapper接口;
(5)ServiceImpl实现类;
(6)Controller层调用接口;
(7)最终接口展示。
实体类是连通着我们的前端接口内容,返回的响应参数都是来自于这儿,参数的数据类型和注释都是来源于这里,所以建立实体类作为我们刚开始编码的第一步毋庸置疑。建立的同时也能知道我们最终是要得到什么值返回给前端,这样我们后面的步骤就围绕着如何得到我们的实体类而行动。
这里想说明的是,因为很多时候返回给前端是一个集合类型,存储着很多的数据。这个时候,我们一般是建立两个实体类,一个实体类用来存储List<>集合,另外一个是用来存储该集合里的内部数据。具体的代码实例如下所示:
其中,我们每个类之前加上一个“@Data”注解,能给我们省去不少的工作量。
@Data注解的作用有二:(1)为当前类提供读写方法,从而不用写get、set方法;(2)为当前类提供 equals()、hashCode()、toString() 方法
@ApiModelProperty注解: 是对各个属性的说明,加上这一注解可以在Swagger中看到响应参数的相关注释内容,让前端工作者能第一时间获取到数据信息提示,提供方便。
package com.hncr.system.domain.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* @ClassName: UserVo
* @Description:用户集合实体类
* @Author: YuHao
* @Date: 2021/12/15
*/
@Data
public class UserVo {
@ApiModelProperty("用户集合")
private List<UserListVo> userListVos;
}
package com.hncr.system.domain.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @ClassName: UserListVo
* @Description:用户类
* @Author: YuHao
* @Date: 2021/12/15
*/
@Data
public class UserListVo {
@ApiModelProperty("姓名")
private String name;
@ApiModelProperty("年龄")
private Integer age;
@ApiModelProperty("性别:(0:男,1:女)")
private Integer sex;
}
完成第一步以后,我们开始写第二个部分。所谓的基于“接口编程”思想大概就是基于Service接口进行的吧!返回类型是我们的UserVo实体类,因为最终要得到的值就是要返回一个集合给前端,所以这里的返回类型便是我们的实体类。(以前的疑问,在这次项目中解决了)具体的代码实例如下所示:
package com.hncr.system.service;
import com.hncr.system.domain.vo.UserVo;
/**
* @InterfaceName: IUserService
* @Description: Service接口
* @Author: YuHao
* @Date: 2021/12/15
*/
public interface IUserService {
UserVo userSummary();
}
其实第三步和第四步是同时进行,之所以将XML文件先写,是因为我们需要将我们的sql语句写好(这个很重要),确定具体需要多少个sql语句才能解决具体的Service接口问题。具体问题具体分析,有时候写一个sql语句就搞定问题了,有时候也需要三四个才行。逻辑不清晰的时候建议去咨询一下前辈或者需求的同事,他们一般都能将你的疑问给解决掉。之前我也发几篇基础版的基于mysql写基本增删查改的sql语句,但是应付项目上的操作还是差点意思,因为牵扯到很多业务逻辑的时候,基本的几个就不够看了。(后续本人将单独增加专说sql实用性语句的博文,大约在冬季哦)
在Navicat中做一些实例操作:根据年龄进行降序排序
SELECT
name,
age,
sex
FROM
`user`
ORDER BY age DESC
(其实在实际项目中要查询或者改变的操作会很多,数据量也会很大,很多时候要对某些个字段做索引操作才会缩短查询的时间,特别说明一下,查询时间超过3秒或者4秒的sql,在前端看来就是一个相当慢的接口了。数据量大的数据库,我们尽量做到只访问一次就好,以避免浪费不必要的时间来影响用户的体验)
在Navicat工具中我们已经查询得到我们想要的效果了,那我们要加入到我们的XML文件中,结合我们的第四步配置namespace、id、resultType等。实例代码如下:
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hncr.system.mapper.UserMapper">
<select id="userSummaryMapper" resultType="java.util.Map">
SELECT
name,
age,
sex
FROM
`user`
ORDER BY age DESC
select>
mapper>
其实在第三步过程中写好我们的sql语句后,就应该跳转到第四步当中了,因为具体的命名空间等是要以Mapper接口来命名的。在上面可知用一条sql语句就搞定了想要的结果,那Mapper接口写一个即可。反正就是sql写了几个,我们对应的就得写几个Mapper接口,其实例代码如下所示:
可以看到这里的返回类型不太一样了哦,因为我之前的文章中是写的List < User >,而在这里是写的List < Map >,区别在于XML文件中的resultType中写明的为:“java.util.Map”,而我上篇文章中对应的resultType中写明的为:“com.example.demo.entity.User”,所以要XML文件中的resultType要和Mapper接口中的一一对应上,否则是查询不到数据,接口报错。在实际的项目中,后续的这种接口方式用得较多,List、Map、List < Map >可以对其做一下了解,看一下就知道如何使用。集合很重要,项目中大多数都是使用了集合,因为太好用了,大家一定掌握好。id对应上我们的Mapper接口名字 “userSUmmaryMapper”。
记住一点就好:XML文件多少个sql,Mapper接口就写多少个;Mapper接口返回类型,接口名称要与XML文件中resultType、id等要一一对应上。遵循这一点,多练习几次也就不会有程序报错了(刚刚开始练手,难免犯错)。
package com.hncr.system.mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
/**
* @InterfaceName: UserService
* @Description:Mapper接口
* @Author: YuHao
* @Date: 2021/12/15
*/
@Repository
public interface UserMapper {
List<Map> userSummaryMapper();
}
到了第五步,这可以算是当前所写后端接口中至关重要的一步了,因为在这里要实现数据的交互,代码逻辑。这里分别对应着流程图中的三个环节 “最终值、中间值、层层计算”,如果我们通过sql语句就能得到我们想要的结果,这个结果称之为 “最终值”,如果通过sql语句只是得到我们中间环节的某些值,这些值我们称之为 “中间值”,需要通过我们在实现类中用相关的逻辑代码(业务代码)进行 “层层计算”。直接能够得到最终值的是最为简单的过程,从数据库拿到数据就可以用,这个接口做起来会非常地快,因为压根就不需要用脑子呀,拿到数据直接 “Set” 就完事了。但是如果所做的项目相对而言逻辑复杂一点的,那么很多时候从数据库拿到的都是原始数据作为我们的中间值,这些数据是要通过我们的 “通用/共用/公用方法” 层层计算才能得到想要的最终值。不管如何,最终都是要Set到我们的对象之中,直接上所对应的实例代码,这样看起来直观明了:
package com.hncr.system.service.impl;
import com.hncr.system.domain.vo.UserListVo;
import com.hncr.system.domain.vo.UserVo;
import com.hncr.system.mapper.UserMapper;
import com.hncr.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @ClassName: UserServiceImpl
* @Description:
* @Author: YuHao
* @Date: 2021/12/15
*/
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private UserMapper userMapper;
List<Map> userSummaryMapper(){
return userMapper.userSummaryMapper();
}
public UserVo userSummary(){
UserVo userVo = new UserVo();
List<Map> list1 = userSummaryMapper();
List<UserListVo> list2 = new ArrayList<>();
for (int i = 0; i < list1.size(); i++) {
UserListVo userListVo = new UserListVo();
Map map = list1.get(i);
userListVo.setName((String) map.get("name"));
userListVo.setAge((Integer) map.get("age"));
userListVo.setSex((Integer) map.get("sex"));
list2.add(userListVo);
}
userVo.setUserListVos(list2);
return userVo;
}
}
以上的代码获取到是最终值,是直接Set到对象之中的。上面的实例代码算是最简单的了,提醒刚入门的小伙伴们,这种方式都是一些较常规做法,是需要掌握的。如果这里出来的是中间值,也不需要怕什么,所谓的 “层层计算” 这些什么的我们都是在大学期间或多或少接触过,我们不管是用什么语言编程都是做过的,不外乎就是“for、if、while、简单的常规算法…”,这个时候让我想到大学为啥那时候要学习数据结构了,因为不管你是码农也好还是算法工程师也罢,把这个学好都是会有用武之地的!!!(当然了,我是学渣,我就没学好,┭┮﹏┭┮)
写完前五步的内容,第六步算是结尾工作了,跟以前的做法类似,这里就是一个调用过程,将相关的注解写好,注入相关的接口方法,然后返回给前端,就完成了我们的一个接口,记住了,这才是仅仅的一个而已,还有更多其他类似或者复杂一丢丢的接口在等着你去写哦~~照惯例上我们的实例代码:
package com.hncr.web.controller.system;
import com.hncr.system.domain.JsonResult;
import com.hncr.system.domain.vo.UserVo;
import com.hncr.system.service.IUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @ClassName: UserController
* @Description:
* @Author: YuHao
* @Date: 2021/12/15
*/
@RestController
@Api(value = "用户信息", tags = "用户信息")
@RequestMapping("/user")
public class UserController {
@Autowired
private IUserService userService;
@ApiOperation(value = "用户信息汇总", notes = "{
" +
" \"msg\": \"操作成功\",
" +
" \"code\": 200,
" +
" \"data\": {
" +
" }
" +
"}")
@GetMapping("UserSummary")
public JsonResult<UserVo> userSummary(){
UserVo userVo = userService.userSummary();
return JsonResult.success(userVo);
}
}
以上的Controller层代码中,很多我都在以前都做过介绍了,这里我就不再累赘了,就是几个非常常用的注解,不记得就多回头看看自己或者同事以前写过的项目代码,还有直接copy使用也可以。主要想说的是,本人这有一个不错的json返回值类,我也将其贴出来,大家可以拿这个用,这是已离职的好朋友分享给我的,其实他技术挺强,但是因为学历限制了他的发展,确实可惜了。这就说明了其实企业还是比较看重学历的,有一个好一点的学历,起步工资还是高不少的!!!加油吧,小伙伴们,下面是具体的代码:
package com.hncr.system.domain;
import com.alibaba.fastjson.JSONObject;
import com.hncr.common.constant.HttpStatus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @ClassName: JsonResult
* @Description: json 返回值
* @Author: YuHao
* @Date: 2021/11/25
*/
@Data
public class JsonResult<T>{
@ApiModelProperty(notes = "响应码")
private Integer code;
@ApiModelProperty(notes = "响应消息")
private String msg;
@ApiModelProperty(notes = "返回数据")
private T data;
/**
* 若没有数据返回,默认状态码为 0,提示信息为“操作成功!”
*/
public JsonResult() {
this.code = HttpStatus.SUCCESS;
this.msg = "success";
}
/**
* 若没有数据返回,可以人为指定状态码和提示信息
* @param code
* @param msg
*/
public JsonResult(int code, String msg) {
this.code = code;
this.msg = msg;
}
/**
* 有数据返回时,状态码为 0,默认提示信息为“操作成功!”
* @param data
*/
public JsonResult(T data) {
this.data = data;
this.code = HttpStatus.SUCCESS;
this.msg = "success";
}
public static JsonResult success(){
return new JsonResult<>();
}
public static <T> JsonResult success(T data){
return new JsonResult(data);
}
public static JsonResult error(String msg){
return new JsonResult(HttpStatus.ERROR,msg);
}
public static JsonResult error(){
return new JsonResult(HttpStatus.ERROR,"error");
}
public static JsonResult error(int code, String msg){
return new JsonResult(code,msg);
}
public static JsonResultBuilder builder(){
return new JsonResultBuilder();
}
public static class JsonResultBuilder{
private JSONObject buildData = new JSONObject();
public JsonResultBuilder put(String key,Object value){
buildData.put(key,value);
return this;
}
public JsonResult get(){
return JsonResult.success(buildData);
}
}
}
最终访问我们的本地地址+“#doc.html”,在Swagger中可以看到我们的接口已经写好了,展示的效果也是按照年龄降序排列的集合。这样的接口,前端的同事拿来就可以用,响应参数、参数数据类型都是非常的清晰。此处我是在已有的项目上做的演示实例,所以Swagger都是已经配置好的,所以此处有是瑕疵的。如果没有配置Swagger的小伙伴应该还需要先百度一下如何配置好Swagger,下个阶段我有时间也整理一下如何配置Swagger。讲实话没有Swagger看不到最终的前端调用效果确实挺难受的,所以这个环节是在我们在写接口之前就要配置好。(这里我写得有点累了,换下次再写吧,O(∩_∩)O哈哈~)
综上所述,这便是基于SpringBoot后端接口的相关流程,有相关的思想也有编写的步骤。有些思想或者步骤我可能写得还不够细,还比较粗糙,但是大致地想法还是表达到位了。我的初衷就是想对于刚入门的小伙伴还是有一些小小的帮助的就好,自己也算是对我的第一个实战项目做大致的总结。最终项目告一段落,界面接口完成了,Bug也改了不少,新增需求也做了一些改善,后续的代码也做了一些优化。成长了不少,也收获了不少,当然也加了很多很多的班…
不管如何,大家还是要参与到实际的项目中,才会逐步收获到一些从来没有遇到过的“惊喜”!!!
编写不易,路过的朋友,如果博客内容对你有所帮助的话,希望能一键三连一下呀,谢谢支持哦!!!