苍穹外卖day02

菜品相关接口开发

图片上传-阿里云OSS

依赖注入

<dependency>
          <groupId>com.aliyun.oss</groupId>
          <artifactId>aliyun-sdk-oss</artifactId>
          <version>${aliyun.sdk.oss}</version>
</dependency>
​

配置密钥

sky:
  alioss:
    endpoint: ${}
    access-key-id: ${}
    access-key-secret: ${}
    bucket-name:  ${}

这里配置的配置信息和关键如密码等信息是分为两个yml来进行配置的,在保护信息、版本控制、配置隔离、团队协作中都起到了一定的作用

配置属性类

@Component
@ConfigurationProperties(prefix = "sky.alioss")
@Data
public class AliOssProperties {
​
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
​
}
​

创建OSS工具类

  /**
     * 文件上传
     *
     * @param bytes
     * @param objectName
     * @return
     */
    public String upload(byte[] bytes, String objectName) {
​
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
​
        try {
            // 创建PutObject请求。
            ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
​
        //文件访问路径规则 https://BucketName.Endpoint/ObjectName
        StringBuilder stringBuilder = new StringBuilder("https://");
        stringBuilder
                .append(bucketName)
                .append(".")
                .append(endpoint)
                .append("/")
                .append(objectName);
​
        log.info("文件上传到:{}", stringBuilder.toString());
​
        return stringBuilder.toString();
    }
}

配置工具类信息,并将工具类交给IOC容器管理

@Configuration
@Slf4j
public class OssConfiguration {
​
    @Bean
    @ConditionalOnMissingBean
    public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties){
        log.info("开始创建阿里云文件上传工具类对象:{}",aliOssProperties);
        return new AliOssUtil(aliOssProperties.getEndpoint(),
                aliOssProperties.getAccessKeyId(),
                aliOssProperties.getAccessKeySecret(),
                aliOssProperties.getBucketName());
    }
}
​

使用工具类实现上传

@RestController
@Slf4j
@RequestMapping("/admin/common")
public class CommonController {
    @Autowired
    private AliOssUtil aliOssUtil;
​
    @PostMapping("/upload")
    @ApiOperation("文件上传")
    public Result<String> upload(MultipartFile file){
        log.info("文件上传:{}",file);
​
​
        try {
            //初始文件名
            String originalFilename = file.getOriginalFilename();
            //取文件后缀名
            String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
            //生成新的文件名, 防止文件名重复
            String obj = UUID.randomUUID().toString() + suffix;
​
​
            //上传文件
            String filePath = aliOssUtil.upload(file.getBytes(), obj);
            return Result.success(filePath);
​
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Result.error("上传文件失败");
    }
}
​

菜品分页查询

@Override
    public PageResult page(DishPageQueryDTO dishPageQueryDTO) {
        PageHelper.startPage(dishPageQueryDTO.getPage(),dishPageQueryDTO.getPageSize());
        Page<DishVO> result = dishMapper.page(dishPageQueryDTO);
        return new PageResult(result.getTotal(),result.getResult());
    }
​
<select id="page" resultType="com.sky.vo.DishVO">
        select d.*, c.name as categoryName from dish d left join category c on d.category_id = c.id
        <where>
            <if test="categoryId != null">
                category_id = #{categoryId}
            </if>
            <if test="name != null and name != ''">
                and name like concat('%',#{name},'%')
            </if>
            <if test="status != null">
                and status = #{status}
            </if>
        </where>
        order by update_time desc
</select>

接收传送参数时尽量用一个封装好的实体类来传送,尽管可能会多传送几个不需要的参数。这样对后续的维护管理提供了便利,同时在一定程度上也避免了在数据传输的出错。注意多表联查返回参数的选择。

查询菜品及其口味

@Override
@Transactional
    public DishVO getDishById(Long id) {
        Dish dish = dishMapper.selectByid(id);
        DishVO dishVO = new DishVO();
        BeanUtils.copyProperties(dish, dishVO);
​
        List<DishFlavor> flavors = dishFlavorMapper.selectByDishId(id);
        dishVO.setFlavors(flavors);
        return dishVO;
    }

@Transactional 维护代码原子性,中途有问题会进行数据回滚,启动类上要开启注解方式的事务管理@EnableTransactionManagement 。

插入菜品

 @Override
    @Transactional
    public void save(DishVO dishVO) {
        Dish dish = new Dish();
        BeanUtils.copyProperties(dishVO, dish);
        dishMapper.save(dish);
​
        Long id = dish.getId();
        List<DishFlavor> flavors = dishVO.getFlavors();
        if(flavors != null && flavors.size() > 0){
            flavors.forEach(dishFlavor -> {
                dishFlavor.setDishId(id);
            });
            //向口味表插入n条数据
            dishFlavorMapper.insertBatch(flavors);
        }
    }

这里如果只是向dish表中插入数据的话 那么自增的id是拿不到的 Long id = dish.getId(); 将出现异常:Cause: java.sql.SQLIntegrityConstraintViolationException: Column 'dish_id' cannot be null。

插入完成后还需要返回一个id数据,在xml中加入属性:useGeneratedKeys="true" keyProperty="id"。useGeneratedKeys属性:用于告知 MyBatis 是否使用数据库的自动生成主键功能。将其设为 true,MyBatis 会借助 JDBC 的 Statement.getGeneratedKeys()方法来获取数据库自动生成的主键值。keyProperty属性:指定了将自动生成的主键值映射到 Java 对象的哪个属性上。当 useGeneratedKeys为 true 时,MyBatis 会把数据库自动生成的主键值赋给 Java 对象中 keyProperty 指定的属性。

<insert id="save" useGeneratedKeys="true" keyProperty="id">
        insert into dish (name, category_id, price, image, description, create_time, update_time, create_user,update_user, status)
        values (#{name}, #{categoryId}, #{price}, #{image}, #{description}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser}, #{status})
    </insert>

删除菜品

@DeleteMapping
    public Result deleteById(@RequestParam List<Long> ids){
        log.info("删除菜品:{}",ids);
​
        dishService.deleteById(ids);
        return Result.success();
    }

@RequestParam 注解的作用是从 HTTP 请求的查询字符串中获取 ids 参数的值,并且把它绑定到方法的 ids 参数上。要是请求中没有提供 ids 参数,就会抛出异常。传入什么类型的数据主要看你用什么接收他。因为如果前端以特定格式传参,Spring 会自动进行类型转换,不只针对逗号分隔的字符串这种形式。

@Override
    @Transactional
    public void deleteById(List<Long> ids) {
        // 判断菜品是否能删除
        // 是否停售
        for(Long id : ids) {
            Dish dish = dishMapper.selectByid(id);
            if(dish != null && dish.getStatus() == StatusConstant.ENABLE)  throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
        }
​
        // 是否关联到其它套餐中了
        for(Long id : ids) {
            Setmeal setmealIdByDishID = setmealDishMapper.getSetmealIdByDishID(id);
            if(setmealIdByDishID != null) throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
        }
​
        for(Long id : ids) {
            dishMapper.deleteById(id);
            dishFlavorMapper.deleteByDishId(id);
        }
    }

总结:

与前面接口相比学到的有:

1、引用了第三方工具阿里云OSS进行图片文件缓存;

2、同一接口进行多个表查询and维护代码原子性;(数据关性时)

3、需要从多个相关表中获取数据,以完整展示业务实体的信息时进行多表联查及返回数据类型选择;(数据相关性时)

4、useGeneratedKeys、keyProperty 指定是否返回数据And接收参数

5、RequestParam 接收参数

套餐管理

功能实现与菜品类似,不做介绍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值