【Spring项目中的Service理解】
创始人
2024-03-02 01:36:34

目录

1. Spring项目中的核心组成部分

2. Spring项目中的Service

 2.1 Service的功能作用

 2.2 Service的实现


1. Spring项目中的核心组成部分

项目的核心组成部分图解:

 

2. Spring项目中的Service

 2.1 Service的功能作用

Service是项目中用于处理业务逻辑的,因为每种数据在做某种操作时,应该都有某些规则:

  • 例如用户尝试登录时,涉及的规则可能包含:用户名对应的用户信息必须存在、提交的密码必须与数据库中存储的密码是匹配的……
  • 例如用户尝试修改密码时,涉及的规则可能包含:当前用户账号必须存在且处于正常状态、提交的原密码必须与数据库中存储的密码是匹配的……
  • 例如用户尝试注册时,涉及的规则可能包含:提交的用户名必须在数据库不存在,提交的手机号码必须在数据库中不存在,提交的电子邮箱必须在数据库中不存在……

这些规则是用于保障数据的有效性、安全性的,使得数据可以随着我们设定的规则而产生或发生变化!

在项目中,关于Service的开发,通常是先定义接口,再定义类实现此接口,接口名通常使用“数据类型Service”这样格式的名称,而实现类通常是在接口名的基础上再添加Impl后缀。

在《阿里巴巴Java开发手册》中的规约:

  • 【强制】对于 Service 和 DAO 类,基于 SOA 的理念,暴露出来的服务一定是接口,内部 的实现类用 Impl 的后缀与接口区别。

 2.2 Service的实现

则在项目的根包下创建service.IAlbumService接口:

public interface IAlbumService {}

然后,在根包下创建service.impl.AlbumServiceImpl类,此类需要实现以上的IAlbumService接口:

public class AlbumServiceImpl implements IAlbumService {}

文件结构如下图所示:

 

然后,需要在接口中设计“添加相册”的抽象方法:

xx xx(xx);

关于抽象方法的名称:可以完全自定义,当前业务是“添加相册”,可以使用addNewadd等。

关于抽象方法的参数列表:大多参数是由客户端提交到控制器,再由控制器调用时传递过来的参数,另外,也可能是控制器处理出来的某些数据(例如Session中的当前登录用户信息),本次的参数应该包含:相册名称、相册简介、相册的排序序号,可以将这3个数据封装到自定义的DTO类中,并使用DTO类型作为参数。

关于抽象方法的返回值类型:仅以操作成功为前提来设计返回值类型,如果操作失败,将抛出异常。

在项目的根包下创建pojo.dto.AlbumAddNewDTO类:

public class AlbumAddNewDTO {private String name;private String description;private Integer sort;
}

并在IAlbumService接口中添加抽象方法:

void addNew(AlbumAddNewDTO albumAddNewDTO);

然后,在AlbumServiceImpl中实现此抽象方法:

@Slf4j
@Service
public class AlbumServiceImpl implements IAlbumService  {@Autowiredprivate AlbumMapper albumMapper;public AlbumServiceImpl() {log.debug("创建业务对象:AlbumServiceImpl");}@Overridepublic void addNew(AlbumAddNewDTO albumAddNewDTO) {// 【稍后再实现】应该保证此相册的名称是唯一的// 创建Album类型的对象// 调用BeanUtils.copyProperties(源对象, 目标对象)将参数的属性值复制到新创建的Album对象中// 调用albumMapper的int insert(Album album)方法插入相册数据}}

初步实现为:

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  {@Autowiredprivate AlbumMapper albumMapper;public AlbumServiceImpl() {log.debug("创建业务对象:AlbumServiceImpl");}@Overridepublic void addNew(AlbumAddNewDTO albumAddNewDTO) {// 【稍后再实现】应该保证此相册的名称是唯一的// 创建Album类型的对象Album album = new Album();// 调用BeanUtils.copyProperties(源对象, 目标对象)将参数的属性值复制到新创建的Album对象中BeanUtils.copyProperties(albumAddNewDTO, album);// 调用albumMapper的int insert(Album album)方法插入相册数据albumMapper.insert(album);}}

完成后,在src/test/java下的根包下创建service.AlbumServiceTests测试类,并在类中编写、执行测试方法:

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 {@AutowiredIAlbumService service;@Testvoid addNew() {AlbumAddNewDTO album = new AlbumAddNewDTO();album.setName("测试数据9998");album.setDescription("测试数据的简介");album.setSort(99); // 注意:sort值必须是[0, 255]之间的service.addNew(album);log.debug("添加数据完成!");}}

在具体实现过程中,还应该保证此次尝试添加的相册的名称是唯一的!

可以通过查询数据库来得知尝试添加的相册的名称是否已经被使用,需要执行的SQL语句可以是:

select id from pms_album where name=?
select count(*) from pms_album where name=?

可以选择使用以上第2种查询来检验相册名称是否已经被使用,则应该在

AlbumMapper.java接口中添加:

int countByName(String name);

并在AlbumMapper.xml中配置SQL:


完成后,应该在AlbumMapperTests.java中编写并执行测试:

@Test
void countByName() {String name = "测试数据";int count = mapper.countByName(name);log.debug("根据名称【{}】统计完成,结果:{}", name, count);
}

接下来,可以在Service的实现过程中进行检查,例如:

String albumName = albumAddNewDTO.getName();
int count = albumMapper.countByName(albumName);
if (count > 0) {// 相册名称已经被使用,将不允许添加此相册,应该抛出异常
} else {// 相册名称没有被使用,可以将此相册数据插入到数据库中
}

提示:以上代码中,由于满足if条件时将抛出异常,所以,可以不必使用else,并且,在后续的编程中,当需要执行某些判断时,应该优先根据“抛出异常”或“终止当前方法的执行”来设计if的条件!即:

if (count > 0) {
    // 相册名称已经被使用,将不允许添加此相册,应该抛出异常
}

// 相册名称没有被使用,可以将此相册数据插入到数据库中

具体实现为:

@Override
public void addNew(AlbumAddNewDTO albumAddNewDTO) {// 应该保证此相册的名称是唯一的String albumName = albumAddNewDTO.getName();int count = albumMapper.countByName(albumName);if (count > 0) {throw new RuntimeException();}// 创建Album类型的对象Album album = new Album();// 调用BeanUtils.copyProperties(源对象, 目标对象)将参数的属性值复制到新创建的Album对象中BeanUtils.copyProperties(albumAddNewDTO, album);// 调用albumMapper的int insert(Album album)方法插入相册数据albumMapper.insert(album);
}

为了避免测试时因为相册名称冲突出现异常而导致测试失败,应该在测试时捕获所抛出的异常,例如:

@Test
void addNew() {AlbumAddNewDTO album = new AlbumAddNewDTO();album.setName("测试数据9998");album.setDescription("测试数据的简介");album.setSort(99); // 注意:sort值必须是[0, 255]之间的try {service.addNew(album);log.debug("添加数据完成!");} catch (RuntimeException e) {log.debug("添加数据失败!名称已经被占用!");}
}

关于以上实现过程中抛出的异常,使用的是RuntimeException,是不合适的!因为程序出现RuntimeException的原因有很多,例如空指针异常、数组下标越界异常、类型转换异常,都属于RuntimeException,如果“相册名称被占用”时抛出RuntimeException,则此方法的调用者很难区分出现异常的真正原因!

通常,建议自定义异常,并且,当视为失败时,抛出此自定义异常的对象!

则在根包下创建ex.ServiceException类,继承自RuntimeException

public class ServiceException extends RuntimeException {
}

提示:本次自定义的异常应该继承自RuntimeException。

然后,在AlbumServiceImpl中添加相册时,如果相册名称被使用,则抛出ServiceException类型的异常:

if (count > 0) {throw new ServiceException();
}

并且,在测试中,捕获的异常也改为ServiceException

try {service.addNew(album);log.debug("添加数据完成!");
} catch (ServiceException e) {log.debug("添加数据失败!名称已经被占用!");
}

个人主页:居然天上楼

感谢你这么可爱帅气还这么热爱学习~~

人生海海,山山而川

你的点赞👍 收藏⭐ 留言📝 加关注✅

是对我最大的支持与鞭策

相关内容

热门资讯

北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...