|
|
|
@ -27,125 +27,177 @@ import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ProductManageController类是一个Spring MVC框架下的RESTful风格的控制器类,用于处理后台商品相关的各种HTTP请求,
|
|
|
|
|
* 提供了诸如获取商品列表、搜索商品、图片上传、管理商品上下架以及保存商品等功能接口,通过依赖注入相关服务层接口实现业务逻辑调用,
|
|
|
|
|
* 并结合缓存工具、工具类等进行数据处理和响应构建,同时使用日志记录关键操作信息及异常情况,方便后续的调试与维护。
|
|
|
|
|
*
|
|
|
|
|
* @Author swg.
|
|
|
|
|
* @Date 2019/1/2 17:32
|
|
|
|
|
* @CONTACT 317758022@qq.com
|
|
|
|
|
* @DESC 后台商品服务
|
|
|
|
|
*/
|
|
|
|
|
@RestController
|
|
|
|
|
// 表明该类是一个Spring RESTful风格的控制器,意味着类中的方法返回值会直接作为HTTP响应体的内容返回,通常用于返回JSON格式的数据等,
|
|
|
|
|
// 适用于构建API接口,方便前后端分离架构下与前端进行数据交互。
|
|
|
|
|
@RequestMapping("/manage/product")
|
|
|
|
|
// 将该控制器类下所有方法对应的请求路径统一设置在 "/manage/product" 前缀之下,便于对后台商品相关接口进行统一管理和分类,
|
|
|
|
|
// 例如后续各个具体方法的请求路径都是基于这个前缀进行拓展的。
|
|
|
|
|
@Slf4j
|
|
|
|
|
// 使用Lombok的 @Slf4j注解自动生成名为log的SLF4J日志记录器,用于在方法执行过程中记录关键信息、异常情况等,方便后续查看日志排查问题、跟踪操作流程。
|
|
|
|
|
public class ProductManageController {
|
|
|
|
|
@Autowired
|
|
|
|
|
private IProductService productService;
|
|
|
|
|
// 通过Spring的依赖注入机制,自动装配IProductService接口的实现类实例,IProductService应该定义了众多与商品业务逻辑相关的方法,
|
|
|
|
|
// 如查询商品列表、获取商品详情、更新商品信息等,在本控制器的多个方法中会调用其相应方法来处理具体的业务操作,实现控制层与业务层的解耦。
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
private IFileService fileService;
|
|
|
|
|
// 注入IFileService接口的实现类实例,该接口大概率是用于处理文件相关操作的服务,比如文件上传功能,在本类的图片上传相关方法中会调用其方法来完成实际的文件上传逻辑。
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
private CommonCacheUtil commonCacheUtil;
|
|
|
|
|
// 注入CommonCacheUtil实例,这应该是一个用于操作缓存(可能是Redis等缓存系统)的工具类,在获取用户信息等需要缓存数据支持的操作中会用到,
|
|
|
|
|
// 通过它可以方便地从缓存中读取、写入数据,提高系统性能,减少重复查询数据库等操作。
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 产品list
|
|
|
|
|
* 处理获取商品列表的HTTP请求的方法,对应请求路径为 "/manage/product/list.do"。
|
|
|
|
|
* 接收页码(pageNum)和每页数量(pageSize)两个参数,默认值分别为1和10,将这两个参数传递给业务层的list方法,获取相应分页的商品列表信息,
|
|
|
|
|
* 并把业务层返回的包含商品列表信息的ServerResponse对象直接返回给客户端,客户端可根据返回结果进行分页展示商品等操作,适用于后台管理系统查看商品列表的场景。
|
|
|
|
|
*
|
|
|
|
|
* @param pageNum 表示要获取的商品列表所在的页码,整数类型,默认值为 "1"(通过 @RequestParam注解指定),
|
|
|
|
|
* 前端可传入具体页码值获取对应页的商品列表,若不传则默认获取第一页商品列表,方便实现分页功能,满足不同查看需求。
|
|
|
|
|
* @param pageSize 表示每页显示的商品数量,整数类型,默认值为 "10",前端可传入期望每页显示的商品个数来灵活控制每页展示数量,若不传则按默认每页10个商品进行分页展示。
|
|
|
|
|
* @return ServerResponse 返回一个ServerResponse类型的对象,用于包装业务层执行获取商品列表操作的结果,
|
|
|
|
|
* 若查询成功,返回的ServerResponse对象中会包含有效的商品列表数据以及表示成功的状态码等信息,
|
|
|
|
|
* 若查询失败(如数据库查询异常、参数错误等原因),则包含相应的错误信息和表示失败的状态码,方便客户端进行相应处理。
|
|
|
|
|
*/
|
|
|
|
|
@RequestMapping("/list.do")
|
|
|
|
|
public ServerResponse list(@RequestParam(value = "pageNum",defaultValue = "1") int pageNum,
|
|
|
|
|
@RequestParam(value = "pageSize",defaultValue = "10") int pageSize){
|
|
|
|
|
return productService.list(pageNum,pageSize);
|
|
|
|
|
public ServerResponse list(@RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
|
|
|
|
|
@RequestParam(value = "pageSize", defaultValue = "10") int pageSize) {
|
|
|
|
|
return productService.list(pageNum, pageSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 产品搜索
|
|
|
|
|
* 处理商品搜索的HTTP请求的方法,对应请求路径为 "/manage/product/search.do"。
|
|
|
|
|
* 接收商品名称(productName)、商品ID(productId)、页码(pageNum)和每页数量(pageSize)四个参数,
|
|
|
|
|
* 将这些参数传递给业务层的search方法,获取符合搜索条件的分页商品列表信息(以PageInfo对象包装),并把业务层返回的ServerResponse对象返回给客户端,
|
|
|
|
|
* 客户端可根据返回结果展示符合搜索条件的商品列表,便于后台管理系统按名称或ID等条件查找特定商品。
|
|
|
|
|
*
|
|
|
|
|
* @param productName 表示要搜索的商品名称,字符串类型,用于在业务层进行模糊搜索(通常会根据商品名称字段进行匹配查找),
|
|
|
|
|
* 若传入具体名称,业务层会筛选出名称包含该关键字的商品列表,若不传则可视为不按名称进行筛选,根据其他条件查找商品。
|
|
|
|
|
* @param productId 表示商品的唯一标识符,整数类型,可用于精确查找特定ID的商品,若传入具体ID值,业务层会优先根据该ID查找对应的商品,
|
|
|
|
|
* 若不传则可结合其他条件(如名称、分页等)进行商品查找,可单独使用也可与其他参数配合来精确或模糊搜索商品。
|
|
|
|
|
* @param pageNum 表示要获取的商品列表所在的页码,整数类型,默认值为 "1",用于实现分页搜索结果展示,前端传入页码值获取对应页的搜索结果,不传则默认获取第一页。
|
|
|
|
|
* @param pageSize 表示每页显示的商品数量,整数类型,默认值为 "10",用于控制每页展示的搜索到的商品个数,前端可传入期望每页数量,不传按默认每页10个商品分页展示。
|
|
|
|
|
* @return ServerResponse<PageInfo> 返回一个ServerResponse类型的对象,其泛型参数为PageInfo,
|
|
|
|
|
* ServerResponse用于包装业务层执行搜索操作的结果,PageInfo包含了分页相关信息(总记录数、总页数等)以及查询到的商品列表数据,
|
|
|
|
|
* 若搜索成功,返回的ServerResponse对象中会包含有效的PageInfo对象及表示成功的状态码等信息,方便客户端分页展示搜索结果,
|
|
|
|
|
* 若搜索失败则包含相应错误信息和表示失败的状态码,供客户端处理。
|
|
|
|
|
*/
|
|
|
|
|
@RequestMapping("search.do")
|
|
|
|
|
public ServerResponse<PageInfo> search(String productName,
|
|
|
|
|
Integer productId,
|
|
|
|
|
@RequestParam(value = "pageNum",defaultValue = "1") int pageNum,
|
|
|
|
|
@RequestParam(value = "pageSize",defaultValue = "10") int pageSize){
|
|
|
|
|
@RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
|
|
|
|
|
@RequestParam(value = "pageSize", defaultValue = "10") int pageSize) {
|
|
|
|
|
|
|
|
|
|
return productService.search(productName,productId,pageNum,pageSize);
|
|
|
|
|
return productService.search(productName, productId, pageNum, pageSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 图片上传
|
|
|
|
|
* 处理图片上传的HTTP请求的方法,对应请求路径为 "/manage/product/upload.do"。
|
|
|
|
|
* 接收一个MultipartFile类型的文件对象(file)以及HttpServletRequest对象(用于获取服务器相关路径信息),
|
|
|
|
|
* 通过调用fileService的upload方法将文件上传到指定路径,然后构建包含文件相关信息(文件名和文件访问URL)的Map对象,
|
|
|
|
|
* 并将其包装在ServerResponse对象中返回给客户端,同时记录上传的图片路径等关键信息到日志中,方便后续查看操作情况及调试。
|
|
|
|
|
*
|
|
|
|
|
* @param file 表示要上传的文件对象,通过 @RequestParam注解指定参数名及可选性(这里非必填,不过实际使用中通常需要上传文件),
|
|
|
|
|
* 是MultipartFile类型,它是Spring提供的用于处理文件上传的接口,可获取文件的各种属性(如文件名、文件内容等),并将文件传输到服务器端进行后续处理。
|
|
|
|
|
* @param request HttpServletRequest类型,用于获取服务器相关的上下文信息,在这里主要是获取服务器上用于存放上传文件的真实路径(通过获取Servlet上下文路径等方式),
|
|
|
|
|
* 以便确定文件上传的具体位置,保证文件能够正确存储在服务器指定的目录下。
|
|
|
|
|
* @return ServerResponse 返回一个ServerResponse类型的对象,用于包装图片上传操作的结果及相关文件信息,
|
|
|
|
|
* 若上传成功,返回的ServerResponse对象中会包含表示成功的状态码以及包含文件路径(uri)和文件访问URL(url)的Map对象等信息,
|
|
|
|
|
* 若上传失败(如文件格式不支持、服务器路径问题等原因),则包含相应的错误信息和表示失败的状态码,方便客户端知晓上传情况并进行相应处理。
|
|
|
|
|
*/
|
|
|
|
|
@RequestMapping("upload.do")
|
|
|
|
|
public ServerResponse upload(@RequestParam(value = "upload_file",required = false) MultipartFile file, HttpServletRequest request){
|
|
|
|
|
public ServerResponse upload(@RequestParam(value = "upload_file", required = false) MultipartFile file, HttpServletRequest request) {
|
|
|
|
|
String path = request.getSession().getServletContext().getRealPath("upload");
|
|
|
|
|
String targetFileName = fileService.upload(file,path);
|
|
|
|
|
String url = "http://img.oursnail.cn/"+targetFileName;
|
|
|
|
|
// 获取服务器上用于存放上传文件的真实路径,通过HttpServletRequest对象获取当前会话(Session)的Servlet上下文(ServletContext),
|
|
|
|
|
// 再获取名为 "upload" 的目录的真实路径,该路径就是后续文件要上传保存的位置,确保文件能够正确存储在服务器指定的地方。
|
|
|
|
|
|
|
|
|
|
String targetFileName = fileService.upload(file, path);
|
|
|
|
|
// 调用fileService的upload方法,将接收到的文件对象和文件保存路径传递进去,执行实际的文件上传操作,
|
|
|
|
|
// 该方法会返回上传后文件在服务器上的目标文件名(可能经过了重命名等处理),方便后续构建文件的访问URL等操作。
|
|
|
|
|
|
|
|
|
|
log.info("【上传的图片路径为:{}】",url);
|
|
|
|
|
String url = "http://img.oursnail.cn/" + targetFileName;
|
|
|
|
|
// 构建文件的访问URL,根据业务需求,将服务器域名(这里是 "http://img.oursnail.cn/")与上传后的目标文件名拼接起来,
|
|
|
|
|
// 得到完整的可用于在浏览器等客户端访问该文件的URL地址,便于后续在前端展示图片或者其他相关操作中使用这个URL来引用上传的文件。
|
|
|
|
|
|
|
|
|
|
log.info("【上传的图片路径为:{}】", url);
|
|
|
|
|
// 使用日志记录上传的图片的访问URL信息,方便后续查看文件上传的结果以及在调试时确认文件是否上传到了正确的位置,同时也有助于排查可能出现的文件访问问题。
|
|
|
|
|
|
|
|
|
|
Map fileMap = Maps.newHashMap();
|
|
|
|
|
fileMap.put("uri",targetFileName);
|
|
|
|
|
fileMap.put("url",url);
|
|
|
|
|
log.info("【返回数据为:{}】",fileMap);
|
|
|
|
|
fileMap.put("uri", targetFileName);
|
|
|
|
|
fileMap.put("url", url);
|
|
|
|
|
// 创建一个Map对象,用于存放文件相关的关键信息,将上传后文件的目标文件名(uri)和构建好的文件访问URL(url)放入Map中,
|
|
|
|
|
// 方便将这些信息统一包装在ServerResponse对象中返回给客户端,使得客户端能够获取到文件的相关详细信息,便于后续展示等操作。
|
|
|
|
|
|
|
|
|
|
log.info("【返回数据为:{}】", fileMap);
|
|
|
|
|
// 再次使用日志记录要返回给客户端的包含文件信息的Map对象内容,便于后续查看返回的数据结构以及排查数据传递过程中可能出现的问题,确保返回的数据符合预期。
|
|
|
|
|
|
|
|
|
|
return ServerResponse.createBySuccess(fileMap);
|
|
|
|
|
// 通过ServerResponse的静态方法createBySuccess创建一个表示成功的ServerResponse对象,并将包含文件信息的fileMap作为成功结果数据传入,
|
|
|
|
|
// 最终将这个ServerResponse对象返回给客户端,告知客户端图片上传操作已成功完成,并传递相关文件信息供客户端使用。
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 产品详情
|
|
|
|
|
* 处理获取商品详情的HTTP请求的方法,对应请求路径为 "/manage/product/detail.do"。
|
|
|
|
|
* 接收一个表示商品ID的整数参数productId,将其传递给业务层的detail方法,获取商品详情信息(以ProductDetailVo对象包装),
|
|
|
|
|
* 并将业务层返回的包含商品详情的ServerResponse对象直接返回给客户端,客户端可根据返回结果展示商品详细信息,常用于后台查看商品具体详情的场景。
|
|
|
|
|
*
|
|
|
|
|
* @param productId 表示要获取详情的商品的唯一标识符,整数类型,通过HTTP请求传递过来,
|
|
|
|
|
* 业务层会依据这个ID从数据库或其他数据源查询并组装对应的商品详情信息(如商品名称、描述、价格、库存等各种属性),
|
|
|
|
|
* 前端需传入准确的商品ID值,若商品不存在等情况会在业务层返回相应的错误信息,包含在ServerResponse对象中返回给客户端。
|
|
|
|
|
* @return ServerResponse<ProductDetailVo> 返回一个ServerResponse类型的对象,其泛型参数为ProductDetailVo,
|
|
|
|
|
* ServerResponse用于包装业务层执行获取商品详情操作的结果,ProductDetailVo是包含商品详细信息的视图对象,
|
|
|
|
|
* 若查询成功,返回的ServerResponse对象中会包含有效的ProductDetailVo对象以及表示成功的状态码等信息,方便客户端展示商品详情,
|
|
|
|
|
* 若查询失败则包含相应错误信息和表示失败的状态码,供客户端处理。
|
|
|
|
|
*/
|
|
|
|
|
@RequestMapping("detail.do")
|
|
|
|
|
public ServerResponse<ProductDetailVo> detail(Integer productId){
|
|
|
|
|
public ServerResponse<ProductDetailVo> detail(Integer productId) {
|
|
|
|
|
return productService.detail(productId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 产品上下架
|
|
|
|
|
* 处理设置商品销售状态(上下架)的HTTP请求的方法,对应请求路径为 "/manage/product/set_sale_status.do"。
|
|
|
|
|
* 接收商品ID(productId)和状态(status)两个整数参数,将它们传递给业务层的set_sale_status方法,执行商品上下架的业务逻辑操作,
|
|
|
|
|
* 并把业务层返回的包含操作结果信息(以字符串形式表示,可能是操作成功与否的提示等)的ServerResponse对象返回给客户端,
|
|
|
|
|
* 客户端可根据返回结果知晓商品上下架操作是否成功,便于后台管理系统对商品的售卖状态进行管控。
|
|
|
|
|
*
|
|
|
|
|
* @param productId 表示要设置销售状态的商品的唯一标识符,整数类型,用于定位数据库中对应的商品记录,
|
|
|
|
|
* 业务层会根据这个ID来更新商品的销售状态,前端需传入准确的商品ID值,确保操作的是正确的商品,若商品不存在等情况会返回相应错误信息。
|
|
|
|
|
* @param status 表示商品的销售状态值,整数类型,具体的取值含义(如1表示上架,0表示下架等)应该由业务层根据业务规则来定义和处理,
|
|
|
|
|
* 通过传入这个参数来告知业务层要将商品设置为对应的销售状态,不同的取值会使业务层执行相应的数据库更新等操作来改变商品的售卖情况。
|
|
|
|
|
* @return ServerResponse<String> 返回一个ServerResponse类型的对象,其泛型参数为String,
|
|
|
|
|
* ServerResponse用于包装业务层执行设置商品销售状态操作的结果,返回的字符串内容可能是操作成功的提示、失败原因等信息,
|
|
|
|
|
* 若操作成功,返回的ServerResponse对象中会包含表示成功的状态码以及相应的成功提示信息等,方便客户端知晓操作情况,
|
|
|
|
|
* 若操作失败则包含相应的错误信息和表示失败的状态码,供客户端处理。
|
|
|
|
|
*/
|
|
|
|
|
@RequestMapping("set_sale_status.do")
|
|
|
|
|
public ServerResponse<String> set_sale_status(Integer productId,Integer status){
|
|
|
|
|
return productService.set_sale_status(productId,status);
|
|
|
|
|
public ServerResponse<String> set_sale_status(Integer productId, Integer status) {
|
|
|
|
|
return productService.set_sale_status(productId, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 新增OR更新产品
|
|
|
|
|
* 处理新增或更新商品的HTTP请求的方法,对应请求路径为 "/manage/product/save.do"。
|
|
|
|
|
* 接收一个Product类型的商品对象参数,将其传递给业务层的saveOrUpdateProduct方法,执行商品的新增或更新的业务逻辑操作,
|
|
|
|
|
* 并把业务层返回的包含操作结果信息(以字符串形式表示,可能是操作成功与否的提示等)的ServerResponse对象返回给客户端,
|
|
|
|
|
* 客户端可根据返回结果知晓商品新增或更新操作是否成功,便于后台管理系统对商品信息进行维护管理。
|
|
|
|
|
*
|
|
|
|
|
* @param product 表示要新增或更新的商品对象,是Product实体类类型,包含了商品的各种属性信息(如名称、描述、价格、库存等),
|
|
|
|
|
* 前端需要按照业务要求构建并传入完整或部分有效的商品对象信息,业务层会根据对象的属性情况(如是否包含ID等)判断
|
|
|
|
|
*/
|
|
|
|
|
@RequestMapping("save.do")
|
|
|
|
|
public ServerResponse<String> productSave(Product product){
|
|
|
|
|
return productService.saveOrUpdateProduct(product);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 富文本上传图片
|
|
|
|
|
* 由于这里如果没有管理员权限,需要回复特定形式的信息,所以校验单独放在这里,zuul过滤器对其直接放过
|
|
|
|
|
*/
|
|
|
|
|
@RequestMapping("richtext_img_upload.do")
|
|
|
|
|
public Map richtextImgUpload(@RequestParam(value = "upload_file",required = false) MultipartFile file, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
|
|
|
|
|
String loginToken = CookieUtil.readLoginToken(httpServletRequest);
|
|
|
|
|
if(StringUtils.isEmpty(loginToken)){
|
|
|
|
|
throw new SnailmallException("用户未登录,无法获取当前用户信息");
|
|
|
|
|
}
|
|
|
|
|
//2.从redis中获取用户信息
|
|
|
|
|
String userStr = commonCacheUtil.getCacheValue(loginToken);
|
|
|
|
|
if(userStr == null){
|
|
|
|
|
throw new SnailmallException("用户未登录,无法获取当前用户信息");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
User user = JsonUtil.Str2Obj(userStr,User.class);
|
|
|
|
|
Map resultMap = Maps.newHashMap();
|
|
|
|
|
if(user == null){
|
|
|
|
|
resultMap.put("success",false);
|
|
|
|
|
resultMap.put("msg","请登录管理员");
|
|
|
|
|
return resultMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String path = httpServletRequest.getSession().getServletContext().getRealPath("upload");
|
|
|
|
|
String targetFileName = fileService.upload(file, path);
|
|
|
|
|
if (StringUtils.isBlank(targetFileName)) {
|
|
|
|
|
resultMap.put("success", false);
|
|
|
|
|
resultMap.put("msg", "上传失败");
|
|
|
|
|
return resultMap;
|
|
|
|
|
}
|
|
|
|
|
String url = PropertiesUtil.getProperty("ftp.server.http.prefix","http://img.oursnail.cn/")+targetFileName;
|
|
|
|
|
resultMap.put("success", true);
|
|
|
|
|
resultMap.put("msg", "上传成功");
|
|
|
|
|
resultMap.put("file_path", url);
|
|
|
|
|
log.info("【返回数据为:{}】",resultMap);
|
|
|
|
|
httpServletResponse.addHeader("Access-Control-Allow-Headers", "X-File-Name");
|
|
|
|
|
return resultMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|