一、课程介绍
-
项目搭建
-
数据持久层实现
-
业务逻辑层实现和测试
-
控制器接口实现
-
整合Swagger
-
整合Mybatis-plus(使用代码生成器)
二、项目搭建(前期回顾)
-
创建Maven项目
-
导入SpringBoot起步依赖(在pom.xml文件中添加以下内容)
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.13</version> <relativePath/> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
-
创建控制器(创建cn.edu.cqie.controller包,并在该包下创建类HelloController,代码如下)
@RestController public class HelloController { @RequestMapping("hello") public String hello(){ return "早上好!"; } }
-
编写启动引导类(在cn.edu.cqie包下创建类App,代码如下)
@SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class,args); } }
-
启动测试(启动App类中的main方法)
三、数据持久层实现
-
整合Mybatis(回顾)
1.1 搭建SpringBoot工程(X)
1.2 添加mybatis起步依赖,添加mysql驱动
-
pom.xml的properties便签中加入以下代码
<mybatis.version>2.2.2</mybatis.version> <mysql.version>8.0.33</mysql.version>
-
pom.xml的dependencies标签中添加依赖
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency>
1.3 编写DataSource和MyBatis相关配置
-
在resources文件夹下创建文件application.yml,并编写文件内容如下
# mysql数据库连接 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db_notice?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true username: root password: 123456 #mybatis配置 mybatis: type-aliases-package: cn.edu.cqie.entity mapper-locations: classpath*:/mapper/*Mapper.xml configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
1.4 定义表和实体类
-
启动mysql,使用Navicat创建并打开数据库db_notice,运行以下Sql
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for t_sys_notice -- ---------------------------- DROP TABLE IF EXISTS `t_sys_notice`; CREATE TABLE `t_sys_notice` ( `id` bigint NOT NULL AUTO_INCREMENT, `title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '标题', `content` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '公告', `create_user_id` bigint NULL DEFAULT NULL COMMENT '创建用户id', `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', `delete_flag` tinyint NULL DEFAULT NULL COMMENT '删除标志(0.正常;1.删除)', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of t_sys_notice -- ---------------------------- INSERT INTO `t_sys_notice` VALUES ('1', '2023年本科分省招生计划一览', '重庆工程学院(教育部代码 12608)。','7', '2022-06-05 22:58:09', '2022-06-29 19:08:43', '1'); INSERT INTO `t_sys_notice` VALUES ('2', '重庆工程学院2023年“专升本”普通类招生章程', '南泉校区:重庆市巴南区南泉街道白鹤林16号(邮编:400056)','7', '2022-06-05 22:58:09', '2022-06-29 19:08:43', '1'); INSERT INTO `t_sys_notice` VALUES ('3', '重庆工程学院2023年招生章程', '第一条 为规范招生工作,切实维护学校和考生的合法权益,确保学校招生工作顺利进行,根据《中华人民共和国教育法》、《中华人民共和国高等教育法》、《重庆工程学院章程》和教育主管部门有关政策和规定,结合重庆工程学院实际情况,特制定本章程。','7', '2022-06-05 22:58:09', '2022-06-29 19:08:43', '0'); INSERT INTO `t_sys_notice` VALUES ('4', '重庆工程学院2023年专升本预录取公示', '公示期:2023年5月29日——2023年6月2日。公示期内,若对预录的学生有异议,请直接向学校教务处及招生办或纪检监察室反映。','7', '2022-06-05 22:58:09', '2022-06-29 19:08:43', '0'); INSERT INTO `t_sys_notice` VALUES ('5', '2023年专升本免试预录学生名单公示', '根据重庆市教育考试院《关于做好2023年重庆市普通高校专升本免试招生有关工作的通知》(渝教考发〔2023〕21号)和《重庆工程学院2023年专升本免试招生章程》相关规定,我校已完成专升本免试招生批次的录取,现将考生预录取情况及录取专业等予以公示。','7', '2022-06-05 22:58:09', '2022-06-29 19:08:43', '1');
-
在项目下创建cn.edu.cqie.entity包,并在包下创建实体类SysNotice,代码如下
@Data public class SysNotice implements Serializable { private static final long serialVersionUID = 1L; private Long id; private String title; private String content; private Long createUserId; private LocalDateTime createTime; private LocalDateTime updateTime; private Integer deleteFlag; }
1.5 编写dao和mapper文件/纯注解开发
-
在项目下创建cn.edu.cqie.mapper包,并在包下创建接口SysNoticeMapper
@Mapper public interface SysNoticeMapper { int save(SysNotice sysNotice); }
-
在resources文件夹下创建mapper文件夹,并在文件夹下创建文件SysNoticeMapper.xml
<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="cn.edu.cqie.mapper.SysNoticeMapper"> <insert id="save" parameterType="sysNotice"> INSERT INTO `t_sys_notice` VALUES (#{id},#{title}, #{content},#{createUserId}, #{createTime}, #{updateTime}, #{deleteFlag}); </insert> </mapper>
1.6 测试
-
引入springboot整合junit的依赖
-
在test/java文件夹下创建包cn.edu.cqie.mapper,并在该包下创建测试类SysNoticeMapperTest
@SpringBootTest(classes = App.class) class SysNoticeMapperTest { @Autowired SysNoticeMapper sysNoticeMapper; @Test void save(){ SysNotice sysNotice=new SysNotice(); sysNotice.setTitle("放假通知"); sysNotice.setContent("重庆高温,放假。"); sysNotice.setCreateUserId(7L); sysNotice.setUpdateTime(LocalDateTime.now()); sysNotice.setCreateTime(LocalDateTime.now()); sysNotice.setDeleteFlag(0); sysNoticeMapper.save(sysNotice); } }
-
四、业务逻辑层实现并测试
-
在项目下创建cn.edu.cqie.mapper包,并在包下创建接口SysNoticeService
public interface SysNoticeService { boolean save(SysNotice sysNotice); }
-
在cn.edu.cqie.mapper包下创建impl包,并在包下创建类SysNoticeServiceImpl,该类实现接口SysNoticeService
@Service public class SysNoticeServiceImpl implements SysNoticeService { @Autowired private SysNoticeMapper sysNoticeMapper; @Override public boolean save(SysNotice sysNotice) { return sysNoticeMapper.save(sysNotice)>0; } }
-
测试业务逻辑层
-
在test/java文件夹下创建包cn.edu.cqie.service,并在该包下创建测试类SysNoticeServiceTest
@SpringBootTest(classes = App.class) class SysNoticeServiceTest { @Autowired SysNoticeService sysNoticeService; @Test void save() { SysNotice sysNotice=new SysNotice(); sysNotice.setTitle("放假通知2"); sysNotice.setContent("重庆高温,放假2。"); sysNotice.setCreateUserId(7L); sysNotice.setUpdateTime(LocalDateTime.now()); sysNotice.setCreateTime(LocalDateTime.now()); sysNotice.setDeleteFlag(0); sysNoticeService.save(sysNotice); } }
-
五、控制器接口实现
-
在cn.edu.cqie包下创建util包,在该包创建结果返回相关的两个类
-
ResultCodeEnum
package cn.edu.cqie.util; import lombok.Getter; /** * 统一返回结果状态信息类 */ @Getter public enum ResultCodeEnum { SUCCESS(200,"成功"), FAIL(201, "失败"), PARAM_ERROR( 202, "参数不正确"), SERVICE_ERROR(203, "服务异常"), DATA_ERROR(204, "数据异常"), DATA_UPDATE_ERROR(205, "数据版本异常"), LOGIN_AUTH(208, "未登陆"), PERMISSION(209, "没有权限"), CODE_ERROR(210, "验证码错误"), LOGIN_DISABLED_ERROR(212, "改用户已被禁用"), REGISTER_MOBLE_ERROR(213, "手机号已被使用"), LOGIN_AURH(214, "需要登录"), LOGIN_ACL(215, "没有权限"), URL_ENCODE_ERROR( 216, "URL编码失败"), ILLEGAL_CALLBACK_REQUEST_ERROR( 217, "非法回调请求"), FETCH_ACCESSTOKEN_FAILD( 218, "获取accessToken失败"), FETCH_USERINFO_ERROR( 219, "获取用户信息失败"), PAY_RUN(220, "支付中"), CANCEL_ORDER_FAIL(225, "取消订单失败"), CANCEL_ORDER_NO(225, "不能取消预约"), SIGN_ERROR(300, "签名错误"), ; private Integer code; private String message; private ResultCodeEnum(Integer code, String message) { this.code = code; this.message = message; } }
-
Result
package cn.edu.cqie.util; import lombok.Data; /** * 全局统一返回结果类 */ @Data public class Result<T> { private Integer code; private String message; private T data; public Result(){} protected static <T> Result<T> build(T data) { Result<T> result = new Result<T>(); if (data != null) result.setData(data); return result; } public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) { Result<T> result = build(body); result.setCode(resultCodeEnum.getCode()); result.setMessage(resultCodeEnum.getMessage()); return result; } public static <T> Result<T> build(Integer code, String message) { Result<T> result = build(null); result.setCode(code); result.setMessage(message); return result; } public static<T> Result<T> ok(){ return Result.ok(null); } /** * 操作成功 * @param data * @param <T> * @return */ public static<T> Result<T> ok(T data){ Result<T> result = build(data); return build(data, ResultCodeEnum.SUCCESS); } public static<T> Result<T> fail(){ return Result.fail(null); } /** * 操作失败 * @param data * @param <T> * @return */ public static<T> Result<T> fail(T data){ Result<T> result = build(data); return build(data, ResultCodeEnum.FAIL); } public Result<T> message(String msg){ this.setMessage(msg); return this; } public Result<T> code(Integer code){ this.setCode(code); return this; } public boolean isOk() { if(this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) { return true; } return false; } }
-
-
在controller包下创建类SysNoticeController
@RestController @RequestMapping("/admin/notice") public class SysNoticeController { @Autowired private SysNoticeService tSysNoticeService; @PostMapping public Result save(@RequestBody SysNotice sysNotice){ if (sysNotice == null){ return Result.fail(); } boolean b = tSysNoticeService.save(sysNotice); if (b){ return Result.ok(); }else{ return Result.fail(); } } }
六、整合Swagger
-
pom.xml的properties便签中加入以下代码
<swagger.version>3.0.0</swagger.version>
-
在pom.xml的dependencies标签中添加Swagger依赖
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>${swagger.version}</version> </dependency>
-
在cn.edu.cqie包下创建config包,在config包下添加Swagger配置类
// 表明当前类是配置类 @Configuration @EnableOpenApi public class SwaggerConfig { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) // 为api选择启动生成器 .select() // 指定要生成api文档的根包 .apis(RequestHandlerSelectors.basePackage("cn.edu.cqie.controller")) // 路径配置 .paths(PathSelectors.any()) .build(); } /** * 创建一个ApiInfo对象 * @return */ private ApiInfo apiInfo() { return new ApiInfoBuilder() // 文档标题 .title("系统通知接口") // 简介 .description("重庆工程学院暑期实训练习") // 作者信息:作者姓名、作者地址、作者邮箱 .contact(new Contact("Pep7Chiao", "http://www.baidu.com", "362142370@qq.com")) // 版本号 .version("1.0") .build(); } }
六、整合Mybatis-plus(使用代码生成器)
-
创建maven项目
-
导入SpringBoot起步依赖和项目所需依赖(在pom.xml文件中添加以下内容)
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.13</version> <relativePath/> </parent> <properties> <java.version>1.8</java.version> <mysql.version>8.0.33</mysql.version> <mybatis-plus.version>3.4.2</mybatis-plus.version> <mybatis-plus-generator.version>3.4.1</mybatis-plus-generator.version> <velocity-engine-core.version>2.3</velocity-engine-core.version> <swagger.version>3.0.0</swagger.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- mysql8驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!-- mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> <!-- 逆向工程代码生成器--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>${mybatis-plus-generator.version}</version> </dependency> <!-- 生成器默认模板引擎--> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>${velocity-engine-core.version}</version> </dependency> <!--swagger--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>${swagger.version}</version> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.6</version> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>3.0.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build>
-
配置application.yml
#服务器端口号 server: port: 8080 # mysql数据库连接 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db_notice?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true username: root password: 123456 #在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射 mybatis-plus: configuration: map-underscore-to-camel-case: true #日志 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #主键生成策略:雪花算法 global-config: db-config: id-type: assign_id
-
编写启动引导类
-
在启动引导类同包下创建代码生成器类CodeGenerator
package cn.edu.cqie; import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.InjectionConfig; import com.baomidou.mybatisplus.generator.config.*; import com.baomidou.mybatisplus.generator.config.po.TableInfo; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class CodeGenerator { /** * <p> * 读取控制台内容 * </p> */ public static String scanner(String tip) { Scanner scanner = new Scanner(System.in); StringBuilder help = new StringBuilder(); help.append("请输入" + tip + ":"); System.out.println(help.toString()); if (scanner.hasNext()) { String ipt = scanner.next(); if (StringUtils.isNotEmpty(ipt)) { return ipt; } } throw new MybatisPlusException("请输入正确的" + tip + "!"); } public static void main(String[] args) { // 代码生成器 AutoGenerator mpg = new AutoGenerator(); // 全局配置 GlobalConfig gc = new GlobalConfig(); String projectPath = System.getProperty("user.dir"); gc.setOutputDir(projectPath + "/src/main/java"); gc.setAuthor("Pep7Chiao"); gc.setOpen(false); // 设置名字 gc.setControllerName("%sController"); gc.setServiceName("%sService"); gc.setServiceImplName("%sServiceImpl"); gc.setMapperName("%sMapper"); // 设置 resultMap gc.setBaseResultMap(true); gc.setBaseColumnList(true); mpg.setGlobalConfig(gc); // 数据源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://localhost:3306/db_notice?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true"); dsc.setDriverName("com.mysql.cj.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("123456"); mpg.setDataSource(dsc); // 自定义配置 InjectionConfig cfg = new InjectionConfig() { @Override public void initMap() { // to do nothing } }; // 包配置 PackageConfig pc = new PackageConfig(); // pc.setModuleName(scanner("模块名")); pc.setParent("cn.edu.cqie"); mpg.setPackageInfo(pc); // 如果模板引擎是 velocity String templatePath = "/templates/mapper.xml.vm"; // 自定义输出配置 List<FileOutConfig> focList = new ArrayList<>(); // 自定义配置会被优先输出 focList.add(new FileOutConfig(templatePath) { @Override public String outputFile(TableInfo tableInfo) { // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!! return projectPath + "/src/main/resources/mapper/" + pc.getModuleName() + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; } }); cfg.setFileOutConfigList(focList); mpg.setCfg(cfg); // 配置模板 TemplateConfig templateConfig = new TemplateConfig(); templateConfig.setXml(null); mpg.setTemplate(templateConfig); // 策略配置 StrategyConfig strategy = new StrategyConfig(); strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); strategy.setEntityLombokModel(true); strategy.setRestControllerStyle(true); // 写于父类中的公共字段 strategy.setInclude(scanner("表名,多个英文逗号分割").split(",")); strategy.setControllerMappingHyphenStyle(true); strategy.setTablePrefix(pc.getModuleName() + "_"); mpg.setStrategy(strategy); mpg.setTemplateEngine(new VelocityTemplateEngine()); mpg.execute(); } }
-
启动CodeGenerator类中的main方法,根据控制台提示输入要处理表格的名字。
-
成功生成后找到mapper包下的接口,在其加上@Mapper
-
配置Swagger用于接口测试
-
config包下配置mybatis-plus分页插件(分页查询需要)
@Configuration @Slf4j public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { log.info("分页插件......"); MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; } }
-
config包下配置mybatis-plus公共字段插入(可选)
package cn.edu.cqie.config; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.time.LocalDateTime; @Configuration @Slf4j public class MyConfig { @Bean public MetaObjectHandler metaObjectHandler(){ return new MetaObjectHandler() { @Override public void insertFill(MetaObject metaObject) { log.info("开始处理 insert方式 公共字段"); metaObject.setValue("createTime", LocalDateTime.now()); metaObject.setValue("updateTime", LocalDateTime.now()); } @Override public void updateFill(MetaObject metaObject) { Long sameId = Thread.currentThread().getId(); log.info("doFilter updateFill update sameId = {}", sameId); log.info("开始处理 update方式 公共字段"); metaObject.setValue("updateTime", LocalDateTime.now()); } }; } }
-
创建util包,创建统一返回结果的工具类ResultCodeEnum和Result
-
生成的实体类的id上添加注解@JsonFormat(shape = JsonFormat.Shape.STRING)
-
在controller包下创建类SysNoticeController,并在该类中完成增删改查接口编写。
package cn.edu.cqie.controller; import cn.edu.cqie.entity.TSysNotice; import cn.edu.cqie.service.TSysNoticeService; import cn.edu.cqie.util.Result; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; /** * <p> * 前端控制器 * </p> * * @author Pep7Chiao * @since 2023-07-18 */ @RestController @RequestMapping("/admin/notice") @Api(tags = "系统通知增删改查") @Slf4j @CrossOrigin public class TSysNoticeController { @Autowired private TSysNoticeService tSysNoticeService; @ApiOperation(value = "单表插入") @PostMapping public Result save(@RequestBody TSysNotice tSysNotice){ if (tSysNotice == null){ return Result.fail(); } boolean b = tSysNoticeService.save(tSysNotice); if (b){ return Result.ok(); }else{ return Result.fail(); } } //接口方法,入口 @ApiOperation(value = "分页查询") //get请求路径 @GetMapping("/{pageNumber}/{pageSize}") public Result getPage(@PathVariable Long pageNumber, @PathVariable Long pageSize){ //构造器 Page<TSysNotice> p = new Page<>(pageNumber,pageSize); Page<TSysNotice> page = tSysNoticeService.page(p); return Result.ok(page); } @ApiOperation(value = "单表修改") @PutMapping //接收Post请求返回json数据 public Result updateNotice(@RequestBody TSysNotice tSysNotice){ boolean b = tSysNoticeService.updateById(tSysNotice); if (b){ return Result.ok(); }else { return Result.fail(); } } @ApiOperation(value = "根据id删除") @DeleteMapping("/{id}") public Result removeById(@PathVariable Long id) { boolean b = tSysNoticeService.removeById(id); if (b){ return Result.ok(); }else { return Result.fail(); } } }