您好,登錄后才能下訂單哦!
本文小編為大家詳細(xì)介紹“Spring Service功能有什么作用”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Spring Service功能有什么作用”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識(shí)吧。
項(xiàng)目的核心組成部分圖解:
Service是項(xiàng)目中用于處理業(yè)務(wù)邏輯的,因?yàn)槊糠N數(shù)據(jù)在做某種操作時(shí),應(yīng)該都有某些規(guī)則:
例如用戶嘗試登錄時(shí),涉及的規(guī)則可能包含:用戶名對(duì)應(yīng)的用戶信息必須存在、提交的密碼必須與數(shù)據(jù)庫(kù)中存儲(chǔ)的密碼是匹配的……
例如用戶嘗試修改密碼時(shí),涉及的規(guī)則可能包含:當(dāng)前用戶賬號(hào)必須存在且處于正常狀態(tài)、提交的原密碼必須與數(shù)據(jù)庫(kù)中存儲(chǔ)的密碼是匹配的……
例如用戶嘗試注冊(cè)時(shí),涉及的規(guī)則可能包含:提交的用戶名必須在數(shù)據(jù)庫(kù)不存在,提交的手機(jī)號(hào)碼必須在數(shù)據(jù)庫(kù)中不存在,提交的電子郵箱必須在數(shù)據(jù)庫(kù)中不存在……
這些規(guī)則是用于保障數(shù)據(jù)的有效性、安全性的,使得數(shù)據(jù)可以隨著我們?cè)O(shè)定的規(guī)則而產(chǎn)生或發(fā)生變化!
在項(xiàng)目中,關(guān)于Service的開發(fā),通常是先定義接口,再定義類實(shí)現(xiàn)此接口,接口名通常使用“數(shù)據(jù)類型Service”這樣格式的名稱,而實(shí)現(xiàn)類通常是在接口名的基礎(chǔ)上再添加Impl
后綴。
在《阿里巴巴Java開發(fā)手冊(cè)》中的規(guī)約:
【強(qiáng)制】對(duì)于 Service 和 DAO 類,基于 SOA 的理念,暴露出來的服務(wù)一定是接口,內(nèi)部 的實(shí)現(xiàn)類用 Impl 的后綴與接口區(qū)別。
則在項(xiàng)目的根包下創(chuàng)建service.IAlbumService
接口:
public interface IAlbumService {}
然后,在根包下創(chuàng)建service.impl.AlbumServiceImpl
類,此類需要實(shí)現(xiàn)以上的IAlbumService
接口:
public class AlbumServiceImpl implements IAlbumService {}
文件結(jié)構(gòu)如下圖所示:
然后,需要在接口中設(shè)計(jì)“添加相冊(cè)”的抽象方法:
xx xx(xx);
關(guān)于抽象方法的名稱:可以完全自定義,當(dāng)前業(yè)務(wù)是“添加相冊(cè)”,可以使用addNew
、add
等。
關(guān)于抽象方法的參數(shù)列表:大多參數(shù)是由客戶端提交到控制器,再由控制器調(diào)用時(shí)傳遞過來的參數(shù),另外,也可能是控制器處理出來的某些數(shù)據(jù)(例如Session中的當(dāng)前登錄用戶信息),本次的參數(shù)應(yīng)該包含:相冊(cè)名稱、相冊(cè)簡(jiǎn)介、相冊(cè)的排序序號(hào),可以將這3個(gè)數(shù)據(jù)封裝到自定義的DTO類中,并使用DTO類型作為參數(shù)。
關(guān)于抽象方法的返回值類型:僅以操作成功為前提來設(shè)計(jì)返回值類型,如果操作失敗,將拋出異常。
在項(xiàng)目的根包下創(chuàng)建pojo.dto.AlbumAddNewDTO
類:
public class AlbumAddNewDTO { private String name; private String description; private Integer sort; }
并在IAlbumService
接口中添加抽象方法:
void addNew(AlbumAddNewDTO albumAddNewDTO);
然后,在AlbumServiceImpl
中實(shí)現(xiàn)此抽象方法:
@Slf4j @Service public class AlbumServiceImpl implements IAlbumService { @Autowired private AlbumMapper albumMapper; public AlbumServiceImpl() { log.debug("創(chuàng)建業(yè)務(wù)對(duì)象:AlbumServiceImpl"); } @Override public void addNew(AlbumAddNewDTO albumAddNewDTO) { // 【稍后再實(shí)現(xiàn)】應(yīng)該保證此相冊(cè)的名稱是唯一的 // 創(chuàng)建Album類型的對(duì)象 // 調(diào)用BeanUtils.copyProperties(源對(duì)象, 目標(biāo)對(duì)象)將參數(shù)的屬性值復(fù)制到新創(chuàng)建的Album對(duì)象中 // 調(diào)用albumMapper的int insert(Album album)方法插入相冊(cè)數(shù)據(jù) } }
初步實(shí)現(xiàn)為:
package cn.tedu.csmall.product.service.impl; import cn.tedu.csmall.product.mapper.AlbumMapper; import cn.tedu.csmall.product.pojo.dto.AlbumAddNewDTO; import cn.tedu.csmall.product.pojo.entity.Album; import cn.tedu.csmall.product.service.IAlbumService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Slf4j @Service public class AlbumServiceImpl implements IAlbumService { @Autowired private AlbumMapper albumMapper; public AlbumServiceImpl() { log.debug("創(chuàng)建業(yè)務(wù)對(duì)象:AlbumServiceImpl"); } @Override public void addNew(AlbumAddNewDTO albumAddNewDTO) { // 【稍后再實(shí)現(xiàn)】應(yīng)該保證此相冊(cè)的名稱是唯一的 // 創(chuàng)建Album類型的對(duì)象 Album album = new Album(); // 調(diào)用BeanUtils.copyProperties(源對(duì)象, 目標(biāo)對(duì)象)將參數(shù)的屬性值復(fù)制到新創(chuàng)建的Album對(duì)象中 BeanUtils.copyProperties(albumAddNewDTO, album); // 調(diào)用albumMapper的int insert(Album album)方法插入相冊(cè)數(shù)據(jù) albumMapper.insert(album); } }
完成后,在src/test/java
下的根包下創(chuàng)建service.AlbumServiceTests
測(cè)試類,并在類中編寫、執(zhí)行測(cè)試方法:
package cn.tedu.csmall.product.service; import cn.tedu.csmall.product.pojo.dto.AlbumAddNewDTO; import cn.tedu.csmall.product.pojo.entity.Album; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @Slf4j @SpringBootTest public class AlbumServiceTests { @Autowired IAlbumService service; @Test void addNew() { AlbumAddNewDTO album = new AlbumAddNewDTO(); album.setName("測(cè)試數(shù)據(jù)9998"); album.setDescription("測(cè)試數(shù)據(jù)的簡(jiǎn)介"); album.setSort(99); // 注意:sort值必須是[0, 255]之間的 service.addNew(album); log.debug("添加數(shù)據(jù)完成!"); } }
在具體實(shí)現(xiàn)過程中,還應(yīng)該保證此次嘗試添加的相冊(cè)的名稱是唯一的!
可以通過查詢數(shù)據(jù)庫(kù)來得知嘗試添加的相冊(cè)的名稱是否已經(jīng)被使用,需要執(zhí)行的SQL語(yǔ)句可以是:
select id from pms_album where name=?
select count(*) from pms_album where name=?
可以選擇使用以上第2種查詢來檢驗(yàn)相冊(cè)名稱是否已經(jīng)被使用,則應(yīng)該在
AlbumMapper.java
接口中添加:
int countByName(String name);
并在AlbumMapper.xml
中配置SQL:
<!-- int countByName(String name); --> <select id="countByName" resultType="int"> SELECT count(*) FROM pms_album WHERE name=#{name} </select>
完成后,應(yīng)該在AlbumMapperTests.java
中編寫并執(zhí)行測(cè)試:
@Test void countByName() { String name = "測(cè)試數(shù)據(jù)"; int count = mapper.countByName(name); log.debug("根據(jù)名稱【{}】統(tǒng)計(jì)完成,結(jié)果:{}", name, count); }
接下來,可以在Service的實(shí)現(xiàn)過程中進(jìn)行檢查,例如:
String albumName = albumAddNewDTO.getName(); int count = albumMapper.countByName(albumName); if (count > 0) { // 相冊(cè)名稱已經(jīng)被使用,將不允許添加此相冊(cè),應(yīng)該拋出異常 } else { // 相冊(cè)名稱沒有被使用,可以將此相冊(cè)數(shù)據(jù)插入到數(shù)據(jù)庫(kù)中 }
提示:以上代碼中,由于滿足if
條件時(shí)將拋出異常,所以,可以不必使用else
,并且,在后續(xù)的編程中,當(dāng)需要執(zhí)行某些判斷時(shí),應(yīng)該優(yōu)先根據(jù)“拋出異常”或“終止當(dāng)前方法的執(zhí)行”來設(shè)計(jì)if
的條件!即:
if (count > 0) {
// 相冊(cè)名稱已經(jīng)被使用,將不允許添加此相冊(cè),應(yīng)該拋出異常 }
// 相冊(cè)名稱沒有被使用,可以將此相冊(cè)數(shù)據(jù)插入到數(shù)據(jù)庫(kù)中
具體實(shí)現(xiàn)為:
@Override public void addNew(AlbumAddNewDTO albumAddNewDTO) { // 應(yīng)該保證此相冊(cè)的名稱是唯一的 String albumName = albumAddNewDTO.getName(); int count = albumMapper.countByName(albumName); if (count > 0) { throw new RuntimeException(); } // 創(chuàng)建Album類型的對(duì)象 Album album = new Album(); // 調(diào)用BeanUtils.copyProperties(源對(duì)象, 目標(biāo)對(duì)象)將參數(shù)的屬性值復(fù)制到新創(chuàng)建的Album對(duì)象中 BeanUtils.copyProperties(albumAddNewDTO, album); // 調(diào)用albumMapper的int insert(Album album)方法插入相冊(cè)數(shù)據(jù) albumMapper.insert(album); }
為了避免測(cè)試時(shí)因?yàn)橄鄡?cè)名稱沖突出現(xiàn)異常而導(dǎo)致測(cè)試失敗,應(yīng)該在測(cè)試時(shí)捕獲所拋出的異常,例如:
@Test void addNew() { AlbumAddNewDTO album = new AlbumAddNewDTO(); album.setName("測(cè)試數(shù)據(jù)9998"); album.setDescription("測(cè)試數(shù)據(jù)的簡(jiǎn)介"); album.setSort(99); // 注意:sort值必須是[0, 255]之間的 try { service.addNew(album); log.debug("添加數(shù)據(jù)完成!"); } catch (RuntimeException e) { log.debug("添加數(shù)據(jù)失?。∶Q已經(jīng)被占用!"); } }
關(guān)于以上實(shí)現(xiàn)過程中拋出的異常,使用的是RuntimeException
,是不合適的!因?yàn)槌绦虺霈F(xiàn)RuntimeException
的原因有很多,例如空指針異常、數(shù)組下標(biāo)越界異常、類型轉(zhuǎn)換異常,都屬于RuntimeException
,如果“相冊(cè)名稱被占用”時(shí)拋出RuntimeException
,則此方法的調(diào)用者很難區(qū)分出現(xiàn)異常的真正原因!
通常,建議自定義異常,并且,當(dāng)視為失敗時(shí),拋出此自定義異常的對(duì)象!
則在根包下創(chuàng)建ex.ServiceException
類,繼承自RuntimeException
:
public class ServiceException extends RuntimeException {}
提示:本次自定義的異常應(yīng)該繼承自RuntimeException。
然后,在AlbumServiceImpl
中添加相冊(cè)時(shí),如果相冊(cè)名稱被使用,則拋出ServiceException
類型的異常:
if (count > 0) { throw new ServiceException(); }
并且,在測(cè)試中,捕獲的異常也改為ServiceException
:
try { service.addNew(album); log.debug("添加數(shù)據(jù)完成!"); } catch (ServiceException e) { log.debug("添加數(shù)據(jù)失敗!名稱已經(jīng)被占用!"); }
讀到這里,這篇“Spring Service功能有什么作用”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。