2025.4.17 修改filebrowser的bug 增加套餐的接口

This commit is contained in:
zhangsan 2025-04-18 18:10:35 +08:00
parent 88c32f02b5
commit c79dc93ba4
13 changed files with 185 additions and 78 deletions

View File

@ -25,4 +25,5 @@ public class MessageConstant {
public static final String ORDER_STATUS_ERROR = "订单状态错误"; public static final String ORDER_STATUS_ERROR = "订单状态错误";
public static final String ORDER_NOT_FOUND = "订单不存在"; public static final String ORDER_NOT_FOUND = "订单不存在";
public static final String ALREADY_EXISTS = "已存在"; public static final String ALREADY_EXISTS = "已存在";
public static final String SYSTEM_ERROR = "系统发生未知异常,正在努力修复中!";
} }

View File

@ -1,7 +1,5 @@
package com.sky.context; package com.sky.context;
import lombok.Data;
public class BaseContext { public class BaseContext {
public static ThreadLocal<Long> threadLocal = new ThreadLocal<>(); public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

View File

@ -1,5 +1,4 @@
package com.sky.utils; package com.sky.utils;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
@ -7,17 +6,16 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import java.io.IOException; import java.io.IOException;
import java.net.URLConnection;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.UUID;
@Slf4j @Slf4j
@AllArgsConstructor @AllArgsConstructor
@ -67,7 +65,8 @@ public class FileBrowserUtil {
// 返回原始返回值假设就是 JWT token 字符串 // 返回原始返回值假设就是 JWT token 字符串
return body; return body;
} else { } else {
throw new IOException("Login failed, HTTP status code: " + statusCode); log.error("Login failed, HTTP status code: " + statusCode);
return "";
} }
} }
} }
@ -80,42 +79,42 @@ public class FileBrowserUtil {
* -H "X-Auth: $TOKEN" \ * -H "X-Auth: $TOKEN" \
* -F "data=@/path/to/local/photo.jpg" //photo.jpg multipart/form-data 的格式上传 * -F "data=@/path/to/local/photo.jpg" //photo.jpg multipart/form-data 的格式上传
*/ */
public String upload(byte[] fileBytes, String objectName) throws IOException { public String uploadAndGetUrl(byte[] fileBytes, String fileName) throws IOException {
// 1.获取唯一文件名 // 1. 登录拿 token
// 2. 构造远程路径固定到 userfiles 目录
String remotePath = "userfiles/" + objectName;
// 3. 获取登录令牌
String token = login(); String token = login();
// 4. URL 编码保留斜杠 // 2. 确定远端存储路径和编码保留斜杠
String remotePath = "store/" + fileName;
String encodedPath = URLEncoder.encode(remotePath, StandardCharsets.UTF_8.toString()) String encodedPath = URLEncoder.encode(remotePath, StandardCharsets.UTF_8.toString())
.replace("%2F", "/"); .replace("%2F", "/");
String url = domain + "/api/resources/" + encodedPath + "?override=true";
// 5. 构建并发送 multipart/form-data 请求 // 3. 根据文件名猜 MIME 类型fallback application/octet-stream
String mimeType = URLConnection.guessContentTypeFromName(fileName);
if (mimeType == null) {
mimeType = "application/octet-stream";
}
// 4. 构造上传 URL
String uploadUrl = domain + "/api/resources/" + encodedPath + "?override=true";
// 5. 执行 Multipart upload
try (CloseableHttpClient client = HttpClients.createDefault()) { try (CloseableHttpClient client = HttpClients.createDefault()) {
HttpPost post = new HttpPost(url); HttpPost post = new HttpPost(uploadUrl);
post.setHeader("X-Auth", token); post.setHeader("X-Auth", token);
post.setEntity(new ByteArrayEntity(fileBytes, ContentType.create(mimeType)));
HttpEntity multipart = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
// name="files"filename 用新生成的 objectName
.addBinaryBody("files", fileBytes, ContentType.APPLICATION_OCTET_STREAM, objectName)
.build();
post.setEntity(multipart);
try (CloseableHttpResponse resp = client.execute(post)) { try (CloseableHttpResponse resp = client.execute(post)) {
int status = resp.getStatusLine().getStatusCode(); int status = resp.getStatusLine().getStatusCode();
String body = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); String body = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
if (status >= 200 && status < 300) { if (status < 200 || status >= 300) {
log.info("上传成功 → {}", remotePath); log.error("文件上传失败: HTTP {}{}", status, body);
return body; return "";
} else {
throw new IOException("上传失败HTTP " + status + ",响应:" + body);
} }
} }
} }
// 6. 拼接 raw 下载链接并返回
String downloadUrl = domain + "/api/raw/" + encodedPath;
log.info("文件下载链接:{}", downloadUrl);
return downloadUrl;
} }
} }

View File

@ -3,6 +3,7 @@ package com.sky.controller.admin;
import com.sky.constant.MessageConstant; import com.sky.constant.MessageConstant;
import com.sky.result.Result; import com.sky.result.Result;
import com.sky.utils.AliOssUtil; import com.sky.utils.AliOssUtil;
import com.sky.utils.FileBrowserUtil;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -12,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.UUID; import java.util.UUID;
@ -26,7 +28,8 @@ public class CommonController {
@Autowired @Autowired
private AliOssUtil aliOssUtil; private AliOssUtil aliOssUtil;
@Autowired
private FileBrowserUtil fileBrowserUtil;
/** /**
* 文件上传 * 文件上传
* @param file * @param file
@ -46,7 +49,8 @@ public class CommonController {
String objectName = UUID.randomUUID().toString() + extension; String objectName = UUID.randomUUID().toString() + extension;
//文件的访问地址 //文件的访问地址
String filePath = aliOssUtil.upload(file.getBytes(), objectName); // String filePath = aliOssUtil.upload(file.getBytes(), objectName);
String filePath = fileBrowserUtil.uploadAndGetUrl(file.getBytes(),objectName);
return Result.success(filePath); return Result.success(filePath);
} catch (IOException e) { } catch (IOException e) {
log.error("文件上传失败:{}", e); log.error("文件上传失败:{}", e);

View File

@ -13,6 +13,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController("adminSetmealController") @RestController("adminSetmealController")
@Slf4j @Slf4j
@Api("套餐相关接口") @Api("套餐相关接口")
@ -24,9 +26,8 @@ public class SetmealController {
@PostMapping @PostMapping
@ApiOperation("新增套餐") @ApiOperation("新增套餐")
@CacheEvict(cacheNames = "setmealCache",key = "#setmealDTO.categoryId")//key: setmealCache::100 @CacheEvict(cacheNames = "setmealCache",key = "#setmealDTO.categoryId")//key: setmealCache::100
public Result addSetmeal(@RequestBody SetmealDTO setmealDTO){ public Result save(@RequestBody SetmealDTO setmealDTO){
log.info("新增套餐"); setmealService.saveWithDish(setmealDTO);
setmealService.addSetmeal(setmealDTO);
return Result.success(); return Result.success();
} }
@GetMapping("/page") @GetMapping("/page")
@ -36,10 +37,9 @@ public class SetmealController {
return Result.success(pageResult); return Result.success(pageResult);
} }
@DeleteMapping @DeleteMapping
@ApiOperation("删除套餐") @ApiOperation("批量删除套餐")
@CacheEvict(cacheNames = "setmealCache",allEntries = true) @CacheEvict(cacheNames = "setmealCache",allEntries = true)
public Result deleteByIds(@RequestParam Long[] ids){ public Result delete(@RequestParam List<Long> ids){
log.info("删除套餐");
setmealService.deleteBatch(ids); setmealService.deleteBatch(ids);
return Result.success(); return Result.success();
} }

View File

@ -40,4 +40,9 @@ public class GlobalExceptionHandler {
return Result.error(MessageConstant.UNKNOWN_ERROR); return Result.error(MessageConstant.UNKNOWN_ERROR);
} }
} }
@ExceptionHandler(Exception.class)
public Result handleAll(Exception ex) {
log.error("未处理的异常:", ex);
return Result.error(MessageConstant.SYSTEM_ERROR);
}
} }

View File

@ -9,13 +9,24 @@ import java.util.List;
@Mapper @Mapper
public interface SetmealDishMapper { public interface SetmealDishMapper {
// @Select("select setmeal_id from setmeal_dish where dish_id=#{id}") /**
// List<Long> queryByDishId(Long id); * 批量保存套餐和菜品的关联关系
*/
void insertBatch(List<SetmealDish> setmealDishes);
void add(SetmealDish setmealDish); /**
@Delete("delete from setmeal_dish where setmeal_id=#{id}") * 根据套餐id删除套餐和菜品的关联关系
void deleteByDishId(Long id); *
* @param setmealId
*/
@Delete("delete from setmeal_dish where setmeal_id=#{setmealId}")
void deleteBySetmealId(Long setmealId);
/**
* 根据套餐id查询
*
* @param setmealId
*/
@Select("select * from setmeal_dish where setmeal_id = #{setmealId}") @Select("select * from setmeal_dish where setmeal_id = #{setmealId}")
List<SetmealDish> getBySetmealId(Long setmealId); List<SetmealDish> getBySetmealId(Long setmealId);

View File

@ -1,5 +1,6 @@
package com.sky.mapper; package com.sky.mapper;
import com.github.pagehelper.Page;
import com.sky.annotation.AutoFill; import com.sky.annotation.AutoFill;
import com.sky.dto.SetmealPageQueryDTO; import com.sky.dto.SetmealPageQueryDTO;
import com.sky.entity.Setmeal; import com.sky.entity.Setmeal;
@ -14,24 +15,58 @@ import java.util.List;
@Mapper @Mapper
public interface SetmealMapper { public interface SetmealMapper {
/**
* 新增套餐
*
* @param setmeal
*/
@AutoFill(OperationType.INSERT) @AutoFill(OperationType.INSERT)
void insert(Setmeal setmeal); void insert(Setmeal setmeal);
List<SetmealVO> queryByCond(SetmealPageQueryDTO setmealPageQueryDTO); /**
* 分页查询
* @param setmealPageQueryDTO
* @return
*/
Page<SetmealVO> pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);
/**
* 根据id查询套餐
* @param id
* @return
*/
@Select("select * from setmeal where id=#{id}") @Select("select * from setmeal where id=#{id}")
Setmeal getById(Long id); Setmeal getById(Long id);
/**
* 根据id删除套餐
* @param id
*/
@Delete("delete from setmeal where id=#{id};") @Delete("delete from setmeal where id=#{id};")
void deleteById(Long id); void deleteById(Long id);
/**
* 修改套餐
*
* @param setmeal
*/
@AutoFill(OperationType.UPDATE) @AutoFill(OperationType.UPDATE)
void update(Setmeal setmeal); void update(Setmeal setmeal);
/** /**
* 动态条件查询套餐 * 动态条件查询套餐
* @param setmeal * @param setmeal
* @return * @return
*/ */
List<Setmeal> list(Setmeal setmeal); List<Setmeal> list(Setmeal setmeal);
/**
* 根据套餐id查询菜品选项
* @param setmealId
* @return
*/
@Select("select sd.name, sd.copies, d.image, d.description " + @Select("select sd.name, sd.copies, d.image, d.description " +
"from setmeal_dish sd left join dish d on sd.dish_id = d.id " + "from setmeal_dish sd left join dish d on sd.dish_id = d.id " +
"where sd.setmeal_id = #{setmealId}") "where sd.setmeal_id = #{setmealId}")
List<DishItemVO> getDishItemBySetmealId(Long id); List<DishItemVO> getDishItemBySetmealId(Long setmealId);
} }

View File

@ -10,11 +10,11 @@ import com.sky.vo.SetmealVO;
import java.util.List; import java.util.List;
public interface SetmealService { public interface SetmealService {
void addSetmeal(SetmealDTO setmealDTO); void saveWithDish(SetmealDTO setmealDTO);
PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO); PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);
void deleteBatch(Long[] ids); void deleteBatch(List<Long> ids);
SetmealVO getByIdWithDish(Long id); SetmealVO getByIdWithDish(Long id);

View File

@ -30,51 +30,78 @@ public class SetmealServiceImpl implements SetmealService {
@Autowired @Autowired
private SetmealMapper setmealMapper; private SetmealMapper setmealMapper;
@Autowired @Autowired
private SetmealDishMapper setmeal_dishMapper; private SetmealDishMapper setmealDishMapper;
@Autowired @Autowired
private DishMapper dishMapper; private DishMapper dishMapper;
@Override @Override
public void addSetmeal(SetmealDTO setmealDTO) { /**
* 新增套餐同时需要保存套餐和菜品的关联关系
*
* @param setmealDTO
*/
public void saveWithDish(SetmealDTO setmealDTO) {
Setmeal setmeal=new Setmeal(); Setmeal setmeal=new Setmeal();
BeanUtils.copyProperties(setmealDTO,setmeal); BeanUtils.copyProperties(setmealDTO,setmeal);
//向套餐表插入数据
setmealMapper.insert(setmeal); setmealMapper.insert(setmeal);
//获取生成的套餐id
Long setmealId = setmeal.getId();
List<SetmealDish> setmealDishList =setmealDTO.getSetmealDishes(); List<SetmealDish> setmealDishList =setmealDTO.getSetmealDishes();
for(SetmealDish setmealDish:setmealDishList){ for(SetmealDish setmealDish:setmealDishList){
setmealDish.setSetmealId(setmeal.getId()); setmealDish.setSetmealId(setmealId);
setmeal_dishMapper.add(setmealDish);
} }
setmealDishMapper.insertBatch(setmealDishList);
} }
/**
* 分页查询
*
* @param setmealPageQueryDTO
* @return
*/
@Override @Override
public PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) { public PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) {
PageHelper.startPage(setmealPageQueryDTO.getPage(),setmealPageQueryDTO.getPageSize()); PageHelper.startPage(setmealPageQueryDTO.getPage(),setmealPageQueryDTO.getPageSize());
List<SetmealVO> setmealVOList=setmealMapper.queryByCond(setmealPageQueryDTO); Page<SetmealVO> page = setmealMapper.pageQuery(setmealPageQueryDTO);
Page<SetmealVO> p= (Page<SetmealVO>) setmealVOList; return new PageResult(page.getTotal(),page.getResult());
PageResult pageResult=new PageResult(p.getTotal(),p.getResult());
return pageResult;
} }
/**
* 批量删除套餐
*
* @param ids
*/
@Override @Override
@Transactional @Transactional
public void deleteBatch(Long[] ids) { public void deleteBatch(List<Long> ids) {
for(Long id:ids){ ids.forEach(id -> {
Setmeal setmeal = setmealMapper.getById(id); Setmeal setmeal = setmealMapper.getById(id);
if(StatusConstant.ENABLE == setmeal.getStatus()){ if (StatusConstant.ENABLE == setmeal.getStatus()) {
//起售中的套餐不能删除 //起售中的套餐不能删除
throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE); throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE);
} }
else{ });
Long setmealId=id;
setmealMapper.deleteById(id); ids.forEach(setmealId -> {
setmeal_dishMapper.deleteByDishId(id); //删除套餐表中的数据
} setmealMapper.deleteById(setmealId);
} //删除套餐菜品关系表中的数据
setmealDishMapper.deleteBySetmealId(setmealId);
});
} }
/**
* 根据id查询套餐和套餐菜品关系
*
* @param id
* @return
*/
@Override @Override
public SetmealVO getByIdWithDish(Long id) { public SetmealVO getByIdWithDish(Long id) {
Setmeal setmeal = setmealMapper.getById(id); Setmeal setmeal = setmealMapper.getById(id);
List<SetmealDish> setmealDishes = setmeal_dishMapper.getBySetmealId(id); List<SetmealDish> setmealDishes = setmealDishMapper.getBySetmealId(id);
SetmealVO setmealVO = new SetmealVO(); SetmealVO setmealVO = new SetmealVO();
BeanUtils.copyProperties(setmeal, setmealVO); BeanUtils.copyProperties(setmeal, setmealVO);
setmealVO.setSetmealDishes(setmealDishes); setmealVO.setSetmealDishes(setmealDishes);
@ -82,7 +109,13 @@ public class SetmealServiceImpl implements SetmealService {
return setmealVO; return setmealVO;
} }
/**
* 修改套餐
*
* @param setmealDTO
*/
@Override @Override
@Transactional
public void update(SetmealDTO setmealDTO) { public void update(SetmealDTO setmealDTO) {
Setmeal setmeal = new Setmeal(); Setmeal setmeal = new Setmeal();
BeanUtils.copyProperties(setmealDTO, setmeal); BeanUtils.copyProperties(setmealDTO, setmeal);
@ -94,18 +127,22 @@ public class SetmealServiceImpl implements SetmealService {
Long setmealId = setmealDTO.getId(); Long setmealId = setmealDTO.getId();
//2删除套餐和菜品的关联关系操作setmeal_dish表执行delete //2删除套餐和菜品的关联关系操作setmeal_dish表执行delete
setmeal_dishMapper.deleteByDishId(setmealId); setmealDishMapper.deleteBySetmealId(setmealId);
List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes(); List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();
setmealDishes.forEach(setmealDish -> { setmealDishes.forEach(setmealDish -> {
setmealDish.setSetmealId(setmealId); setmealDish.setSetmealId(setmealId);
}); });
//3重新插入套餐和菜品的关联关系操作setmeal_dish表执行insert //3重新插入套餐和菜品的关联关系操作setmeal_dish表执行insert
for(SetmealDish setmealDish:setmealDishes){ setmealDishMapper.insertBatch(setmealDishes);
setmeal_dishMapper.add(setmealDish);
}
} }
/**
* 套餐起售停售
*
* @param status
* @param id
*/
@Override @Override
public void startOrStop(Integer status, Long id) { public void startOrStop(Integer status, Long id) {
//起售套餐时判断套餐内是否有停售菜品有停售菜品提示"套餐内包含未启售菜品,无法启售" //起售套餐时判断套餐内是否有停售菜品有停售菜品提示"套餐内包含未启售菜品,无法启售"

View File

@ -1,5 +1,5 @@
server: server:
port: 8080 port: 8085
spring: spring:
profiles: profiles:

View File

@ -3,9 +3,12 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" > "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.SetmealDishMapper"> <mapper namespace="com.sky.mapper.SetmealDishMapper">
<insert id="add"> <insert id="insertBatch" parameterType="list">
insert into setmeal_dish (setmeal_id,dish_id,name,price,copies) insert into setmeal_dish (setmeal_id,dish_id,name,price,copies)
values (#{setmealId},#{dishId},#{name},#{price},#{copies}) values
<foreach collection="setmealDishes" item="sd" separator=",">
(#{sd.setmealId},#{sd.dishId},#{sd.name},#{sd.price},#{sd.copies})
</foreach>
</insert> </insert>
<select id="getSetmealIdsByDishIds" resultType="java.lang.Long"> <select id="getSetmealIdsByDishIds" resultType="java.lang.Long">
select setmeal_id from setmeal_dish where dish_id in select setmeal_id from setmeal_dish where dish_id in

View File

@ -21,13 +21,27 @@
</set> </set>
where id=#{id} where id=#{id}
</update> </update>
<select id="queryByCond" resultType="com.sky.vo.SetmealVO"> <select id="pageQuery" resultType="com.sky.vo.SetmealVO">
select c.*,d.name from setmeal as c left outer join category as d on c.category_id=d.id select
s.*,c.name categoryName
from
setmeal s
left join
category c
on
s.category_id = c.id
<where> <where>
<if test="categoryId!=null">and c.category_id=#{categoryId}</if> <if test="name != null">
<if test="name!=null and name!=''">and c.name like concat('%',#{name},'%')</if> and s.name like concat('%',#{name},'%')
<if test="status!=null">and c.status=#{status}</if> </if>
<if test="status != null">
and s.status = #{status}
</if>
<if test="categoryId != null">
and s.category_id = #{categoryId}
</if>
</where> </where>
order by s.create_time desc
</select> </select>
<select id="list" resultType="com.sky.entity.Setmeal"> <select id="list" resultType="com.sky.entity.Setmeal">
select * from setmeal select * from setmeal