利用spring boot和mybatis构建接口
想做一个心情收纳箱的软件,帮助我在心情低落的时候找找合适的排忧途径。人嘛,总有低落的时候,只有在低落的时候能够快速恢复,才能不会更低落
注:因为这是真实项目下来的,所以我把import去掉了
1、首先应该弄明白 mapper.xml 和 mapper 之间是如何联系起来的
看一个例子
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xxxx.xxx.xxx.mapper.ChangeUserInfoMapper">
<resultMap id="changeUserInfoMap" type="ChangeUserInfoDto">
<result column="user_name" property="userName"/>
<result column="email" property="email" />
<result column="org_name" property="orgName"/>
<result column="org_web_site" property="orgWenSite" />
<result column="image" property="image"/>
</resultMap>
<select id="queryById" parameterType="Long" resultMap="changeUserInfoMap">
SELECT
A.user_name
FROM t_user AS A
WHERE A.uid = #{id}
</select>
<update id="updateUserInfo">
UPDATE t_user SET
<if test="orgName != null">
org_name = #{orgName}
</if>
<if test="orgWebSite != null">
org_web_site = #{orgWebSite}
</if>
<if test="image != null">
image = #{image}
</if>
WHERE uid = #{uid}
</update>
</mapper>
namespace 就是该mapper.xml对应的实体类mapper
@Mapper
@Component(value = "changeUserInfoMapper")
public interface ChangeUserInfoMapper {
ChangeUserInfoDto queryById(long id);
Integer updateUserInfo(@Param("uid") long uid, @Param("orgName") String orgName, @Param("orgWebSite") String orgWebSite,@Param("image") byte[] image);
}
实体mapper中的方法名就是mapper.xml中的id,这是一一对照关系。在mapper.java中方法中的参数,如果大于一个,要使用@Param注解,否则mybatis找不到对应的参数,@Param中的名字应该与mapper.xml中的变量名保持一致。如果只有一个参数,@Param就无所谓要不要了。方法的返回类型与.xml中的resultMap类型一致。可以自定义resultMap类型,自定义的resultMap的type最好使用通用的数据传输Dto,这样使得数据传输具有统一性,方便代码的编写和清晰。
以上是基于spring boot开发情况下,spring boot会自动对mapper.xml和mapper进行配置,如果非spring boot环境,需要自己手动写。
2、然后要知道做一个数据交换的 DTO 的必要性
数据传输对象,把在一个接口中需要的所有必要参数全部放到一个POJO中,包括从数据库中获取的和从用户处得到的。从开始接收用户数据开始,一直都使用这一个数据传输对象,可以有效避免代码参数过多变得特别凌乱不好维护的场景。同时,写成dto后可以有效的把逻辑层剥离出来。
public class ChangeUserInfoDto {
private long uid;
private String userName;
private String email;
private String orgName;
private String orgWebSite;
private byte[] image;
private boolean validate;
public long getUid() {
return uid;
}
public void setUid(long uid) {
this.uid = uid;
}
public String getUserName() {
return userName;
}
public String getEmail() {
return email;
}
public String getOrgName() {
return orgName;
}
public String getOrgWebSite() {
return orgWebSite;
}
public byte[] getImage() {
return image;
}
public void setValidate(boolean validate) {
this.validate = validate;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setEmail(String email) {
this.email = email;
}
public void setImage(byte[] image) {
this.image = image;
}
public void setOrgName(String orgName) {
this.orgName = orgName;
}
public void setOrgWebSite(String orgWebSite) {
this.orgWebSite = orgWebSite;
}
public boolean isValidate() {
return validate;
}
}
3、service 如何与mapper联系起来
service层一般是处理的核心,在处理业务逻辑的时候,可能会需要持久化数据进行支持,这时候只需要调用相应的mapper就可以了。所以,在service中采用构造器注入的方式将mapper注入到service中。
@Service
public class ChangeUserInfoServiceImpl implements ChangeUserInfoService {
private ChangeUserInfoMapper changeUserInfoMapper;
public ChangeUserInfoServiceImpl(ChangeUserInfoMapper mapper){ this.changeUserInfoMapper = mapper;}
@Override
public ChangeUserInfoDto checkUser(long id) {
ChangeUserInfoDto dto = changeUserInfoMapper.queryById(id);
if (Objects.nonNull(dto)){
if (dto.getUserName() != null){
dto.setValidate(true);
dto.setUserName("");
dto.setUid(id);
}
}
return dto;
}
@Override
public Integer updateUserInfo(ChangeUserInfoDto dto) {
int ans = changeUserInfoMapper.updateUserInfo(dto.getUid(), dto.getOrgName(), dto.getOrgWebSite(), dto.getImage());
return ans;
}
}
这里要说明的是,将service定义成接口,然后使用类来实现service的接口式编程,有助于控制器中对service的自动注入,自动注入会找到实现该service接口的Impl,然后自动注入到代码中。如果同时有多个类实现了该service,自动注入的时候就会报错,得在优先级最高的Impl上面加上@primary的注释,这样就会自动注入该Impl了。
public interface ChangeUserInfoService {
ChangeUserInfoDto checkUser(long id);
Integer updateUserInfo(ChangeUserInfoDto dto);
}
4、创建rest ful api 要会的东西
支撑的东西研究完了,应该开始写接收请求了,控制器。为了能够更好的解释上面说的内容,这里如何进行调用的我就没有模糊化
首先,
@Controller告诉spring boot这是一个控制器
然后通过@Autowired自动注入需要的service
@RequestMapping里面主要有俩参数,value代表请求的路径,可以是一个列表,即多个路径用同一个方法处理。method指的是请求的方法
@ResponseBody告诉spring boot返回的结果就是返回值,如果不加这个注释,spring boot会到模板中去找对应的页面,如果要返回一个键值对,可以使用Map<String, Object>的方式,这里,我只返回了一个数字。
如果传进来的是一个文件,使用类似
@RequestParam(“userImage”) final MultipartFile file的方法就可以了
其中括号中的变量名应该与传递的参数的名字保持一致,后面的变量名是一个别名。
@Controller
@SessionAttributes(Constant.USER_SESSION_NAME)
public class UserInfoController {
@Autowired
ChangeUserInfoService changeUserInfoService;
@RequestMapping(value = Path.CHANGE_PROPERTY, method = RequestMethod.POST)
@ResponseBody
public Integer changeProperty(@ModelAttribute(Constant.USER_SESSION_NAME) User user,
@RequestParam("newinfo") final String newinfo,
@RequestParam("flag") final int flag){
long uid = user.getUserId();
ChangeUserInfoDto dto = changeUserInfoService.checkUser(uid);
if (Objects.nonNull(dto) && dto.isValidate()){
// TODO: 2018/12/13 执行更新操作
if (flag == 1){
dto.setOrgName(newinfo);
}
int flagdo = 0;
if (flag == 2){
boolean url = WebSiteUtil.checkUrl(newinfo);
if (url){
dto.setOrgWebSite(newinfo);
}else {
flagdo = 1;
}
}
if (flagdo == 0){
int check = changeUserInfoService.updateUserInfo(dto);
if (check > 0){
return 1;
}else {
return 0;
}
}
}
return 0;
}
@RequestMapping(value = Path.ChANGE_USER_IMAGE, method = RequestMethod.POST)
@ResponseBody
public Integer changeUserImage(@ModelAttribute(Constant.USER_SESSION_NAME) User user,
@RequestParam("userImage") final MultipartFile file) throws IOException {
if (!file.isEmpty()){
long uid =user.getUserId();
ChangeUserInfoDto dto = changeUserInfoService.checkUser(uid);
if (Objects.nonNull(dto) && dto.isValidate()){
dto.setImage(file.getBytes());
int check = changeUserInfoService.updateUserInfo(dto);
if (check > 0){
return 1;
}
}
return 0;
}else {
return 0;
}
}
}
5、把一连串操作串联起来就成啦
根据上面的讨论流程,我们可以发现执行流程是这样的 请求->Controller->service->mapper->mapper.xml->mapper->service->Controller->响应这样的。
6、接口开发的真实开发流程
根据执行流程,可以发现其实我们的开发流程也应该是先写Controller,然后写需要完成什么样的服务,需要进行哪些数据传输交互,然后设计DTO,数据库需要做哪些支持,然后设计mapper,编写代码就可以了。
下一篇: DetailView内匿名函数不可用
推荐阅读
-
Spring boot Mybatis整合构建Rest服务(超细版)
-
spring boot整合mybatis利用Mysql实现主键UUID的方法
-
MyBatis与Spring的整合(传统的DAO方式和Mapper接口方式)
-
MyBatis Mapper在Spring中的扫描和接口代理
-
spring boot配置MySQL数据库连接、Hikari连接池和Mybatis的简单配置方法
-
现有web系统替换成Spring Boot2框架 之21 同时支持带项目名和不带项目名访问,web访问强制https,接口保持http访问 Spring Boot2带项目名不带项目名httpshttp
-
spring boot和mybatis入门
-
使用Spring Boot和OAuth构建安全的SPA
-
Spring Boot如何利用拦截器加缓存完成接口防刷操作
-
Spring boot和mybatis结合时mapper的扫描