天天看點

利用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>      

注意:如果select的傳回值是Integer等類型,應該寫成resultType而不是resultMap

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、把一連串操作串聯起來就成啦

6、接口開發的真實開發流程