[SpringBoot]Service与Controller层

目录

关于Service

关于Controller

关于各组件的处理流程

补充:

Service保证数据完整性是怎么体现的?

 以下代表复制属性,把来源adminAddNewParam复制到目标 admin里面


关于Service

Service的核心价值在于:组织业务流程,处理业务逻辑,以保证数据的完整性、有效性、安全性。

在编写代码时,强烈建议先定义Service的接口,然后,自定义编写其实现类。  

关于“新增相册”,先自定义POJO类,用于封装相关参数!在项目的根包下创建pojo.param.AlbumAddNewParam类:

@Data
public class AlbumAddNewParam implements Serializable {
    private String name;
    private String description;
    private Integer sort;
}

然后,在项目的根包下创建service.IAlbumService,并在接口中添加“新增相册”的抽象方法:

public interface IAlbumService {
    void addNew(AlbumAddNewParam albumAddNewParam);
}

然后,在项目的根包下创建service.impl.AlbumServiceImpl类,实现以上接口:

public class AlbumServiceImpl implements IAlbumService {}

关于Service方法的声明:

  • 返回值类型:仅以操作成功为前提来设计返回值

    • 操作失败全部通过抛出异常来表示

  • 方法名称:自定义

  • 参数列表:如果参数数量较多,且具有相关性,可以封装,如果参数数量较少,或不具备相关性,则逐一声明

  • 抛出异常:抛出所有遇到的异常,如果只会出现RuntimeException,并不需要使用throws关键字显式的声明 

在具体实现之前,为了明确的表示出错的原因是因为所设计的规则,应该先自定义异常类型,并且,在规则验证不通过时,抛出自定义异常类型,后续,在调用此方法时,根据是否抛出了自定义异常类型来判断是否符合所设计的规则。

在项目的根包下创建ex.ServiceException类,继承自RuntimeException类,并添加基于父级异常的、带String message参数的构造方法:

public class ServiceException extends RuntimeException {

    public ServiceException(String message) {
        super(message);
    }
    
}

关于自定义异常需要继承自RuntimeException,原因主要有2点:

  • 如果继承的不是RuntimeException,抛出异常的方法必须显式的使用throws声明抛出,并且,Service方法的调用者(Controller)也必须在代码中明确的try...catchthrows,而开发实践中,会使用Spring MVC框架的全局异常处理机制来统一处理异常,则Service、Controller等组件都必须将异常抛出,这是固定的做法,所以,没有必要继承自非RuntimeException并反复声明抛出异常

  • 基于Spring JDBC的事务管理将根据RuntimeException进行回滚

然后,在AlbumServiceImpl类上添加@Service注解,在类中自动装配AlbumMapper类型的属性,并实现接口中定义的抽象方法,在实现过程中,如果判断违背了所设计的规则,应该抛出自定义的ServiceException类型的异常对象:  

@Service
public class AlbumServiceImpl implements IAlbumService {

    @Autowired
    private AlbumMapper albumMapper;

    @Override
    public void addNew(AlbumAddNewParam albumAddNewParam) {
        // 检查相册名称是否被占用,如果被占用,则抛出异常
        QueryWrapper<Album> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", albumAddNewParam.getName()); // name='参数中的相册名称'
        int countByName = albumMapper.selectCount(queryWrapper);
        if (countByName > 0) {
            String message = "添加相册失败,相册名称已经被占用!";
            // System.out.println(message);
            throw new ServiceException(message);
        }

        // 将相册数据写入到数据库中
        Album album = new Album();
        BeanUtils.copyProperties(albumAddNewParam, album);
        album.setGmtCreate(LocalDateTime.now());
        album.setGmtModified(LocalDateTime.now());
        albumMapper.insert(album);
    }

}

完成后,应该在src/test/java下的根包下创建service.AlbumServiceTests测试类,测试以上方法:

@SpringBootTest
public class AlbumServiceTests {

    @Autowired
    IAlbumService service;

    @Test
    void addNew() {
        AlbumAddNewParam albumAddNewParam = new AlbumAddNewParam();
        albumAddNewParam.setName("测试数据-00003");
        albumAddNewParam.setDescription("测试数据简介-00003");
        albumAddNewParam.setSort(99);

        try {
            service.addNew(albumAddNewParam);
            System.out.println("添加成功!");
        } catch (ServiceException e) {
            System.out.println(e.getMessage());
        } catch (Throwable e) {
            System.out.println("添加失败!出现了某种异常!");
            e.printStackTrace();
        }
    }

}

关于Controller

通过控制器接收并处理请求

在通过控制器处理请求之前,需要添加对应的依赖项:spring-boot-starter-web。  

提示:所有Spring提供的以spring-boot-starter作为名称前缀的依赖项(例如spring-boot-starter-web),都包含了Spring Boot的基础依赖项(spring-boot-starter)。

则将项目中原本依赖的spring-boot-starter改为spring-boot-starter-web

在项目的根包下创建cn.tedu.csmall.product.controller.AlbumController,在类中添加方法处理“添加相册”的请求:

@RestController
@RequestMapping("/album")
public class AlbumController {

    @Autowired
    private IAlbumService albumService;

    // http://localhost:8080/album/add-new?name=TestName001&description=TestDescription001&sort=99
    @RequestMapping("/add-new")
    public String addNew(AlbumAddNewParam albumAddNewParam) {
        try {
            albumService.addNew(albumAddNewParam);
            return "添加成功!";
        } catch (ServiceException e) {
            return e.getMessage();
        } catch (Throwable e) {
           return "添加失败!出现了某种异常!";
        }
    }

}

完成后,启动项目,在浏览器的地址栏中使用 http://localhost:8080/album/add-new?name=TestName001&description=TestDescription001&sort=99 即可测试访问。

 


关于各组件的处理流程


补充:

Service保证数据完整性是怎么体现的?

用户提交的数据不够表中的字段时,就需要我们在Service层进行补全,普通用户操作界面提交的数据就是不完整的,因为有一部分数据我们不放心他去提交,比如时间。但是他不提提交,数据库里面又有,我们就去补全。

 以下代表复制属性,把来源adminAddNewParam复制到目标 admin里面

BeanUtils.copyProperties(adminAddNewParam, admin);

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值