700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 电商生鲜网站开发(三)——后台开发:商品分类模块-Redis/Swagger/统一身份校验/IDEA技巧

电商生鲜网站开发(三)——后台开发:商品分类模块-Redis/Swagger/统一身份校验/IDEA技巧

时间:2020-10-20 19:17:57

相关推荐

电商生鲜网站开发(三)——后台开发:商品分类模块-Redis/Swagger/统一身份校验/IDEA技巧

电商生鲜网站开发(三)——后台开发:商品分类模块-Redis/Swagger/统一身份校验/IDEA技巧

分类层级

在商品分类上需要继续做归类操作

分类设置成三级

层级太深的弊端:对用户不友好,不利于查找;后台管理部方便

分类模块主要功能

分类数据的设置

根据分类的父级目录递归查找

接口与表设计

/a2272062968/article/details/123385857

分类接口开发

跟用户接口类似

参数校验

在前台传入的实体类定义中参数上增加对应规则的注解即可,可以增加多个规则

package com.imooc.mall.model.request;import lombok.Data;import javax.validation.constraints.Max;import javax.validation.constraints.NotNull;import javax.validation.constraints.Size;/*** 描述:AddCategoryReq*/@Datapublic class AddCategoryReq {@Size(min = 2,max = 5)private String name;@NotNull@Max(3)private Integer type;@NotNull(message = "parentId不能为null")private Integer parentId;@NotNull(message = "orderNum不能为null")private Integer orderNum;}

增加校验后即可拦截不规范的数据,我们捕捉注解抛出的异常就可以获取到提示信息

去之前的GloalExceptionHandler拦截异常类中编写异常过滤器

package com.learn2333.mall.exception;//拦截异常@ControllerAdvice@Slf4jpublic class GloalExceptionHandler {private final Logger logger = LoggerFactory.getLogger(GloalExceptionHandler.class);@ExceptionHandler(Exception.class)@ResponseBodypublic Object handleException(Exception e) {logger.error("Default Exception:", e);return ApiRestResponse.error(MallExceptionEnum.SYSTEM_ERROR);}@ExceptionHandler(MallException.class)@ResponseBodypublic Object handleImoocMallException(MallException e) {logger.error("MallException:", e);return ApiRestResponse.error(e.getCode(), e.getMessage());}/*** 方法参数不合规处理* @param e* @return*/@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseBodypublic ApiRestResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {logger.error("MethodArgumentNotValidException:", e);return handleBindingResult(e.getBindingResult());}private ApiRestResponse handleBindingResult(BindingResult result) {//把异常处理为对外暴露的提示List<String> list = new ArrayList<>();if (result.hasErrors()) {List<ObjectError> allErrors = result.getAllErrors();// itlifor (ObjectError objectError : allErrors) {String message = objectError.getDefaultMessage();list.add(message);}}if (list.size() == 0) {return ApiRestResponse.error(MallExceptionEnum.REQUEST_PARAM_ERROR);}return ApiRestResponse.error(MallExceptionEnum.REQUEST_PARAM_ERROR.getCode(), list.toString());}}

异常枚举所有错误码

package com.learn2333.mall.exception;/*** 描述: 异常枚举*/public enum MallExceptionEnum {NEED_USER_NAME(10001,"用户名不能为空"),NEED_PASSWORD(10002,"密码不能为空"),NEED_TOO_SHORT(10003,"密码长度不能小于8位"),NAME_EXISTED(10004,"不允许重名"),INSERT_FAILED(10005,"插入失败,请重试"),WRONG_PASSWORD(10006,"登录密码错误,请重试"),NEED_LOGIN(10007,"用户未登录,请登录"),UPDATE_FAILD(10008,"更新失败,请重试"),NEED_ADMIN(10009,"无管理员权限"),PARA_NOT_NULL(10010,"参数不能为空"),CREATE_FAILED(10011,"新增失败"),REQUEST_PARAM_ERROR(10012,"参数错误"),DELETE_FAILED(10013,"删除失败"),MKDIR_FAILED(10014,"文件夹创建失败"),UPLOAD_FAILED(10015,"图片上传失败"),NOT_SALE(10016,"商品状态不可售"),NOT_ENOUGH(10017,"商品库存不足"),CART_EMPTY(10018,"购物车已勾选的商品为空"),NO_ENUM(10019,"未找到对应的枚举"),NO_ORDER(10020,"订单不存在"),NO_YOUR_ORDER(10021,"订单不属于你"),WRONG_ORDER_STATUS(10021,"订单不符"),SYSTEM_ERROR(20000,"系统异常");/*** 异常码*/Integer code;/*** 异常信息*/String msg;MallExceptionEnum(Integer code, String msg) {this.code = code;this.msg = msg;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}}

Swagger自动生成API文档

引入依赖

pom

<dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version></dependency>

开启

入口类上增加@EnableSwagger2注解开启自动生成api文档

修改配置

config包下修改配置文件

package com.learn2333.mall.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;/*** 配置Swagger*/@Configurationpublic class SpringFoxConfig {//访问http://localhost:8083/swagger-ui.html可以看到API文档@Beanpublic Docket api() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.any()).paths(PathSelectors.any()).build();}private ApiInfo apiInfo() {return new ApiInfoBuilder().title("生鲜网站").description("").termsOfServiceUrl("").build();}}

配置MVC Config Swagger地址映射

package com.learn2333.mall.config;import com.mon.Constant;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** 描述:配置Swagger地址映射*/@Configurationpublic class MallWebMvcConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {// registry.addResourceHandler("/images/**").addResourceLocations("file:" + Constant.FILE_UPLOAD_DIR);registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");}}

使用方法

在写好的接口上增加@ApiOperation注解

@ApiOperation("后台删除目录")@PostMapping("admin/category/delete")@ResponseBodypublic ApiRestResponse deleteCategory(@RequestParam Integer id) {categoryService.delete(id);return ApiRestResponse.success();}

访问

http://localhost:8083/swagger-ui.html

即可展示所有的接口和接口名,在此页面也可以直接简单调试接口

统一校验管理员身份

编写过滤器

package com.learn2333.mall.filter;import com.mon.Constant;import com.learn2333.mall.model.pojo.User;import com.learn2333.mall.service.UserService;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpServletResponseWrapper;import javax.servlet.http.HttpSession;import org.springframework.beans.factory.annotation.Autowired;/*** 描述:管理员校验过滤器*/public class AdminFilter implements Filter {@AutowiredUserService userService;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpSession session = request.getSession();User currentUser = (User) session.getAttribute(Constant.MALL_USER);if (currentUser == null) {PrintWriter out = new HttpServletResponseWrapper((HttpServletResponse) servletResponse).getWriter();out.write("{\n"+ " \"status\": 10007,\n"+ " \"msg\": \"NEED_LOGIN\",\n"+ " \"data\": null\n"+ "}");out.flush();out.close();return;}//校验是否是管理员boolean adminRole = userService.checkAdminRole(currentUser);if (adminRole) {filterChain.doFilter(servletRequest, servletResponse);} else {PrintWriter out = new HttpServletResponseWrapper((HttpServletResponse) servletResponse).getWriter();out.write("{\n"+ " \"status\": 10009,\n"+ " \"msg\": \"NEED_ADMIN\",\n"+ " \"data\": null\n"+ "}");out.flush();out.close();}}@Overridepublic void destroy() {}}

配置过滤器生效范围

这样,当请求路径带有以下范围时,过滤器拦截生效,进行上面的管理员身份校验

package com.learn2333.mall.config;import com.learn2333.mall.filter.AdminFilter;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/*** 描述:Admin过滤器的配置*/@Configurationpublic class AdminFilterConfig {@Beanpublic AdminFilter adminFilter() {return new AdminFilter();}@Bean(name = "adminFilterConf")public FilterRegistrationBean adminFilterConfig() {FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();filterRegistrationBean.setFilter(adminFilter());filterRegistrationBean.addUrlPatterns("/admin/category/*");filterRegistrationBean.addUrlPatterns("/admin/product/*");filterRegistrationBean.addUrlPatterns("/admin/order/*");filterRegistrationBean.setName("adminFilterConf");return filterRegistrationBean;}}

分页功能

@Overridepublic PageInfo listForAdmin(Integer pageNum, Integer pageSize) {PageHelper.startPage(pageNum, pageSize, "type,order_num");List<Category> categoryList = categoryMapper.selectList();PageInfo pageInfo = new PageInfo(categoryList);return pageInfo;}

用户分类接口列表-递归查询

@Overridepublic List<CategoryVO> listCategoryForCustomer(Integer parentId) {ArrayList<CategoryVO> CategoryVOList = new ArrayList<>();recursivelyFindCategories(CategoryVOList, parentId);return CategoryVOList;}private void recursivelyFindCategories(List<CategoryVO> categoryVOList, Integer parentId) {//递归获取所有子类别,并组合成为一个"目录树"List<Category> categoryList = categoryMapper.selectCategoriesByParentId(parentId);if (!CollectionUtils.isEmpty(categoryList)) {for (Category category : categoryList) {CategoryVO categoryVO = new CategoryVO();BeanUtils.copyProperties(category, categoryVO);categoryVOList.add(categoryVO);//将此目录的子目录进行递归填充recursivelyFindCategories(categoryVO.getChildCategory(), categoryVO.getId());}}}

利用SpringBoot集成Redis

引入pom

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>

配置连接

application.properties 配置连接(默认端口号、密码为空)

spring.redis.host=localhostspring.redis.port=6379spring.redis.password=

增加启动注解

启动类上增加@EnableCaching注解,打开缓存功能

测试redis

测试redis是否启动:终端进入redis/src目录 - ./redis-cli - ping回应PONG说明启动了

Redis内容:/a2272062968/article/details/119866634

在需要缓存的方法上增加注解

在目录列表实现方法上面增加注解,此方法的Cache就配置好了

@Override@Cacheable(value = "listCategoryForCustomer")public List<CategoryVO> listCategoryForCustomer(Integer parentId) {ArrayList<CategoryVO> CategoryVOList = new ArrayList<>();recursivelyFindCategories(CategoryVOList, parentId);return CategoryVOList;}

配置Redis

还要配置Redis,编写Redis的配置类,配置超时时间等

package com.learn2333.mall.config;import java.time.Duration;import org.springframework.cache.annotation.EnableCaching;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.cache.RedisCacheConfiguration;import org.springframework.data.redis.cache.RedisCacheManager;import org.springframework.data.redis.cache.RedisCacheWriter;import org.springframework.data.redis.connection.RedisConnectionFactory;/*** 描述:缓存的配置类*/@Configuration@EnableCachingpublic class CachingConfig {@Beanpublic RedisCacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {RedisCacheWriter redisCacheWriter = RedisCacheWriter.lockingRedisCacheWriter(connectionFactory);RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();cacheConfiguration = cacheConfiguration.entryTtl(Duration.ofSeconds(30));//超时时间30sRedisCacheManager redisCacheManager = new RedisCacheManager(redisCacheWriter, cacheConfiguration);return redisCacheManager;}}

需要缓存的实体类实现接口

要想让分类写入缓存还必须为对应的实体类实现Serializable接口

public class CategoryVO implements Serializable

验证缓存生效

**方法一:**在30秒内调用的缓存方法都会返回之前查询的缓存内容;可以在需要缓存的内容方法中打断电测试,调用方法时没有执行方法而是直接从缓存中读取,速度显著提升

**方法二:**在终端使用keys查看redis中的内容

IDEA调试技巧

统一开关

让所有断点失效

条件断点

指定条件成立时生效

单步调试

表达式求值

可以输入任意表达式查询内部的内容

总结

知识点:参数校验、Swagger、统一鉴权、Redis整合、调试功能

开发常见问题:参数手动校验、项目不用缓存、不善用调试

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。