Service:
业务,它是Mapper的调用者,也是被Controller调用的组件。
Service的主要作用是设计业务流程、业务逻辑,以保障数据的有效性、安全性、完整性。
Service在代码中的表现通常包含接口与实现类。
Service的方法声明原则:
返回值类型:仅以操作成功为前提来设计 失败将通过抛出异常来表示 方法名称:自定义 参数列表:通常根据客户端提交的数据来设计,对于相关的数据,可以封装 添加相册--Service 业务规则:相册名称必须唯一。
需要实现“检查相册名称是否被占用”的检查功能,可以通过数据库查询来实现,相关的SQL语句大致是:
select * from pms_album where name=?
或者:
select count(*) from pms_album where name=? 在AlbumMapper.java接口中添加新的抽象方法:
int countByName(String name); 在AlbumMapper.xml中配置以上抽象方法映射的SQL语句:
<!-- int countByName(String name); -->
在AlbumMapperTests中编写并执行测试:
在项目的根包下创建pojo.dto.AlbumAddNewDTO类,用于封装客户端提交的数据(客户端会把数据提交到Controller,而Controller会使用这些数据来调用Service的方法):
@Data
public class AlbumAddNewDTO implements Serializable {
private String name;
private String description;
private Integer sort;
}
在项目的根包下创建service.IAlbumService接口:
public interface IAlbumService {
void addNew(AlbumAddNewDTO albumAddNewDTO);
}
在项目的根包下创建service.impl.AlbumServiceImpl类,实现以上接口:
@Service public class AlbumServiceImpl implements IAlbumService {
@Autowired
private AlbumMapper albumMapper;public void addNew(AlbumAddNewDTO albumAddNewDTO) {
// 调用参数对象的getName()得到尝试添加的相册的名称
// 调用Mapper对象的countByName()执行统计查询
// 判断统计结果是否大于0
// -- 是:名称被占用,抛出异常,例如:throw new RuntimeException()
// 创建Album对象
// 调用BeanUtils.copyProperties(源,目标)将参数对象中的属性复制到Album对象中
// 调用Mapper对象的insert()执行插入相册数据
}
}
完成后,在src/test/java的根包下创建service.AlbumServiceTests测试类,编写并执行测试:
@Slf4j
@SpringBootTest
public class AlbumServiceTests {
@Autowired
IAlbumService service;@Test
void xxx() {
}
}
关于异常
为了避免捕获并处理异常时产生歧义,在Service的实现过程中,如果需要通过抛出异常来表示某种“失败”,应该抛出自定义异常!
在项目的根包下创建ex.ServiceException类,继承自RuntimeException:
package cn.tedu.csmall.product.ex;
public class ServiceException extends RuntimeException { }
关于继承自RuntimeException,主要原因有:
第1点:因为Spring MVC框架有统一处理异常的机制,所以,Service方法始终抛出异常,Controller方法也始终抛出异常,则没有必要通过throws关键字声明抛出,如果继承的父级异常不是RuntimeException,必须在各Service方法和Controller方法上都声明抛出 第2点:Spring JDBC处理事务时,只会根据RuntimeException执行回滚 添加相册-Controller 首先,需要在pom.xml中添加spring-boot-starter-web依赖项,目前,项目中已经添加spring-boot-starter依赖项,而spring-boot-starter-web包含此依赖项,所以,只需要将现有的spring-boot-starter改为spring-boot-starter-web即可:
<!-- Spring Boot支持Spring MVC的依赖项 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
在项目的根包下创建controller.AlbumController类,添加@RestController,表示此类是一个响应数据的控制器类,并在类中自动装配IAlbumService接口类型的对象,在类中添加方法处理“添加相册”的请求:
@RestController
public class AlbumController {
@Autowired
private IAlbumService albumService;
// http://localhost:8080/album/add-new?name=test001&description=hahahaha&sort=100
// http://localhost:8080/album/add-new
@RequestMapping("/album/add-new")
public int addNew(AlbumAddNewDTO albumAddNewDTO) {
try {
albumService.addNew(albumAddNewDTO);
return 1;
} catch (ServiceException e) {
return 0;
}
}
}
关于以上处理请求的方法:
返回值类型:根据期望响应到客户端的信息类型来设计,如果返回值类型是自定义的数据类型,则响应时会由Spring MVC框架自动转换成JSON格式的字符串
方法名称:自定义 参数列表: 关于响应结果类型 在项目的根包下创建web.JsonResult类,在类中声明需要响应到客户端的数据对应的属性:
@Data public class JsonResult implements Serializable {
private Integer state;
private String message;
}
然后,在控制器类中,在处理请求的方法上,将返回值类型改为以上类型,并在方法中返回此类型的对象:
@RequestMapping("/album/add-new")
public JsonResult addNew(AlbumAddNewDTO albumAddNewDTO) {
try {
albumService.addNew(albumAddNewDTO);
JsonResult jsonResult = new JsonResult();
jsonResult.setState(1);
jsonResult.setMessage("添加相册成功!");
return jsonResult;
} catch (ServiceException e) {
JsonResult jsonResult = new JsonResult();
jsonResult.setState(0);
jsonResult.setMessage("添加相册失败,相册名称已经被占用!");
return jsonResult;
}
}
完成后,重启项目,再次访问,可以看到服务器端响应了JSON格式的结果
以上代码中,使用了较多的代码来完成“创建对象、为属性赋值”,非常臃肿,可以考虑简化:
在JsonResult中添加全参数构造方法
在JsonResult中设计链式的Setter
或直接在类上添加@Accessors(chain = true)
在JsonResult中添加静态方法
例如,在JsonResult中添加静态方法:
public static JsonResult ok() {
JsonResult jsonResult = new JsonResult();
jsonResult.state = 1;
return jsonResult;
}
public static JsonResult fail(Integer state, String message) {
JsonResult jsonResult = new JsonResult();
jsonResult.state = state;
jsonResult.message = message;
return jsonResult;
}
则控制器类中处理请求的方法可以调整为:
@RequestMapping("/album/add-new")
public JsonResult addNew(AlbumAddNewDTO albumAddNewDTO) {
try {
albumService.addNew(albumAddNewDTO);
return JsonResult.ok();
} catch (ServiceException e) {
return JsonResult.fail(0, "添加相册失败,相册名称已经被占用!");
}
}
根据ID删除相册--Mapper 实现此功能需要执行的SQL语句大致是:
delete from pms_album where id=?
根据ID删除相册--Service 在IAlbumService中添加抽象方法:
void delete(Long id);
在AlbumServiceImpl中实现以上抽象方法:
public void delete(Long id) { // 调用Mapper对象的getStandardById()执行查询 // 判断查询结果是否为null // 是:数据不存在,抛出异常
// 调用Mapper对象的deleteById()方法执行删除
}
在AlbumServiceTests中编写并执行测试:
根据ID删相册--Controller 在AlbumController中添加处理此请求的方法:
// http://localhost:8080/album/delete?id=1
@RequestMapping("/album/delete")
public JsonResult delete(Long id) {
try {
albumService.delete(id);
return JsonResult.ok();
} catch (ServiceException e) {
return JsonResult.fail(0, "删除相册失败,尝试删除的相册数据不存在!");
}
}
希望对你有所帮助!