SpringBoot —— Service层
-
概念
- 在实际开发中,Service层主要负责业务模块的逻辑应用设计。首先设计接口,再设计接口的实现类
- Service层用于封装项目中一些通用的业务逻辑,有利于业务逻辑的独立性和重复利用性
-
Service层与@Service注解
- 写在前面
- 详细讲解Service层之前,我们先来简单说一下后端通用的一个服务架构“MVC”模型
- M指的是Model,意为“模型”,指的是数据库在服务架构内的映射,用于访问和操作数据库中的数据。在Java中,我们一般使用Dao层表示
- V指的是View,意为“视图”,在之前前后端不分离的情况下,页面由模板引擎构建好(实际上就是去自动化的插入代码),再返回给前端渲染。前后端分离流行以后,后端基本上只负责数据的处理,以及将处理后的数据返回即可。在Java中,我们一般用Service层表示
- C指的是Controller,意为“控制器”,负责转发请求到Service层
- 综上所述,后端返回数据的一般步骤:
- Dao层访问数据库,拿到对应的数据或执行相关的操作
- Service层拿到Dao层的结果进行处理
- Controller层返回数据
- @Service注解
- Service层的实现类须使用@Service注解予以标注,被@Service标注的类称为服务类
- @Service注解属于Component组件,可以被扫描器扫描到
- 写在前面
-
Service层的实现过程
-
大多数的SpringBoot项目采用接口模式实现Service层
-
步骤
- 定义一个Service层的接口,在这个接口中定义用于传递和处理数据的方法
- 定义一个Service层的接口的实现类,使用@Service注解标注
- 这个实现类的作用有两个:
- 实现Service层的接口中的业务方法
- 执行Dao层中用于访问、处理数据的操作
- 这个实现类的作用有两个:
- 在服务类的对象被自动地创建并注册成Bean之后,其他Component组件即可直接注入这个Bean
-
示例
ProductService接口:
public interface ProductService { String getName(); }
ProductServiceImpl实现类:
@Service public class ProductServiceImpl implements ProductService{ @Override public String getName() { return "kaiven"; } }
TestController控制器:
@RestController public class TestController { @Autowired ProductServiceImpl productService; @RequestMapping("/test") public String test() { return productService.getName(); } }
-
-
同时存在多个实现类的情况
-
概念
- 实际的开发过程中,一个Service层的接口可能会针对多种业务场景而存在多个实现类
-
按照实现类的服务名称映射服务类对象
-
概念
- 被@Service标注的实现类被称作服务类,这个实现类的对象被称作服务类的对象。服务类的对象会被自动创建,并注册为Bean,而Bean的名称就是类名的首字母小写版
- 其他Component组件即可通过指定的Bean的名称的方式注入与服务类对象对应的Bean
-
示例
server.TranslateService:
public interface TranslateService { String translate(String word); }
server.impl.English2ChineseImpl:
@Service public class English2ChineseImpl implements TranslateService { @Override public String translate(String word) { if("hello".equalsIgnoreCase(word)) return "你好"; return "抱歉,我还没有学习过这个!"; } }
server.impl.French2ChineseImpl:
@Service public class French2ChineseImpl implements TranslateService { @Override public String translate(String word) { if("Allô?".equalsIgnoreCase(word)) return "你好"; return "我还没有学过这个嘞!"; } }
controller.TranslateController:
@RestController public class TranslateController { @Autowired TranslateService english2ChineseImpl; // 英译汉 @Autowired TranslateService french2ChineseImpl; // 法译汉 @RequestMapping("/english") public String english(String word) { return english2ChineseImpl.translate(word); } @RequestMapping("/french") public String french(String word) { return french2ChineseImpl.translate(word); } }
-
-
按照@Service的value属性映射服务类的对象
-
概念
- @Service注解中,只包含一个value属性,value属性是@Service注解的默认属性
- 为value属性赋值后,就相当于在创建与服务类的对象对应的Bean时确定了Bean的名称
-
示例
service.TranscriptsService:
public interface TranscriptsService { void sort(List<Double> score); }
service.impl.ASCTranscriptsServiceImpl:
@Service("asc") public class ASCTranscriptsServiceImpl implements TranscriptsService { @Override public void sort(List<Double> score) { Collections.sort(score); } }
service.impl.DESCTranscriptsServiceImpl:
@Service("desc") public class DESCTranscriptsServiceImpl implements TranscriptsService { @Override public void sort(List<Double> score) { score.sort(new Comparator<Double>() { @Override public int compare(Double o1, Double o2) { return o2.compareTo(o1); } }); } }
controller.TranscriptsController:
@RestController public class TranscriptsController { @Autowired TranscriptsService asc; @Autowired TranscriptsService desc; @RequestMapping("/asc") public String asc(Double a, Double b, Double c) { List<Double> list = new ArrayList<Double>(List.of(a,b,c)); asc.sort(list); StringBuilder sb = new StringBuilder(); list.forEach(e -> sb.append(e.toString()).append("\n")); return sb.toString(); } @RequestMapping("/desc") public String desc(Double a, Double b, Double c) { List<Double> list = new ArrayList<>(List.of(a,b,c)); desc.sort(list); StringBuilder sb = new StringBuilder(); list.forEach(e -> sb.append(e.toString()).append("\n")); return sb.toString(); } }
-
-
-
不采用接口模式的服务类
-
概念
- 实际开发中,一些功非常简单的服务可以不采用接口模式,直接创建服务类病使用@Service注解标注即可
-
示例
service.VerifyService:
@Service public class VerifyService { public boolean chineseName(String name) { String match = "^[\\u4E00-\\u9FA5]{2,4}$"; return name != null && name.matches(match); } }
controller.VerifyController:
@RestController public class VerifyController { @Autowired VerifyService verifyService; @RequestMapping("/verify/name") public String verifyName(String name){ return verifyService.chineseName(name) ? "是中文名" : "不是中文名"; } }
-
-
@Service和@Repository的联系与区别
- 联系
- 两个注解都被@Component注解标注,都可以被扫描器扫描到
- 区别
- 其实区别不大,主要是为了方便开发人员从字面上就能够判断出某个服务是业务服务,还是数据库服务
- @Service标注Service层,@Repository标注Dao层
- 联系