尚品汇-(三)

maven之packaging标签

 

 

(1)项目创建父模块

首先设置 下Maven

 

Maven:仓库地址:这里是腾讯云仓库 

 

作为父模块,src没用,干掉src

这里我们是Maven创建的项目,想要项目变成SpringBoot的项目,需要引入SpringBoot父工程:也可以通过SpringBoot的方式创建项目

引入依赖管理:这里是对依赖进行管理,并不是引入实际的依赖

 <!--定义jar包的版本号--><properties><java.version>1.8</java.version><cloud.version>Hoxton.SR8</cloud.version><alibaba.version>2.2.5.RELEASE</alibaba.version><gmall.version>1.0-SNAPSHOT</gmall.version><mybatis-plus.version>3.4.1</mybatis-plus.version><mysql.version>5.1.46</mysql.version><swagger.version>2.7.0</swagger.version><lombok.version>1.18.10</lombok.version><fastjson.version>1.2.29</fastjson.version><redisson.version>3.15.3</redisson.version><pool2.version>2.6.0</pool2.version><httpclient.version>4.5.13</httpclient.version></properties><!--配置dependencyManagement锁定依赖的版本 并不是实际的依赖。--><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${cloud.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${alibaba.version}</version><type>pom</type><scope>import</scope></dependency><!--mybatis-plus 持久层--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><!--swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>${swagger.version}</version></dependency><!--swagger ui--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>${swagger.version}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency><!-- redisson 分布式锁--><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>${redisson.version}</version></dependency><!-- spring2.X集成redis所需common-pool2--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>${pool2.version}</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>${httpclient.version}</version></dependency></dependencies></dependencyManagement>

作为父工程的话,加个<packaging> pom  </packaging>

(2) 搭建common父模块

common:公共模块父节点

common-util:工具类模块,所有模块都可以依赖于它

service-utilservice服务的工具包,包含service服务的公共配置类,所有                              service模块依赖于它

 

点击gmall-parent,选择New–>Module,操作如下

commmon也是个父工程加:

引入依赖:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><scope>provided </scope></dependency><!--lombok用来简化实体类:需要安装lombok插件--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId></dependency><!--用来转换json使用 {JavaObject - json | json - JavaObject}--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId></dependency><!-- 服务调用feign --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><scope>provided </scope></dependency></dependencies>

2.1搭建common-util模块

点击common,选择New–>Module,操作如下

修改pom:不声明就是jar,可以声明一下,说明他是jar包

添加依赖:

 <dependencies><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId></dependency></dependencies>

在下面添加工具类:

GmallException :自定义全局异常类: 

package com.atguigu.gmall.common.execption;import com.atguigu.gmall.common.result.ResultCodeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/*** 自定义全局异常类*/
@Data
@ApiModel(value = "自定义全局异常类")
public class GmallException extends RuntimeException {@ApiModelProperty(value = "异常状态码")private Integer code;/*** 通过状态码和错误消息创建异常对象* @param message* @param code*/public GmallException(String message, Integer code) {super(message);this.code = code;}/*** 接收枚举类型对象* @param resultCodeEnum*/public GmallException(ResultCodeEnum resultCodeEnum) {super(resultCodeEnum.getMessage());this.code = resultCodeEnum.getCode();}@Overridepublic String toString() {return "GuliException{" +"code=" + code +", message=" + this.getMessage() +'}';}
}

Result:全局统一返回结果类 

package com.atguigu.gmall.common.result;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/*** 全局统一返回结果类**/
@Data
@ApiModel(value = "全局统一返回结果")
public class Result<T> {@ApiModelProperty(value = "返回码")private Integer code;@ApiModelProperty(value = "返回消息")private String message;@ApiModelProperty(value = "返回数据")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> 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;}
}

ResultCodeEnum:统一返回结果状态信息类 

package com.atguigu.gmall.common.result;import lombok.Getter;/*** 统一返回结果状态信息类**/
@Getter
public enum ResultCodeEnum {SUCCESS(200,"成功"),FAIL(201, "失败"),SERVICE_ERROR(2012, "服务异常"),ILLEGAL_REQUEST( 204, "非法请求"),PAY_RUN(205, "支付中"),LOGIN_AUTH(208, "未登陆"),PERMISSION(209, "没有权限"),SECKILL_NO_START(210, "秒杀还没开始"),SECKILL_RUN(211, "正在排队中"),SECKILL_NO_PAY_ORDER(212, "您有未支付的订单"),SECKILL_FINISH(213, "已售罄"),SECKILL_END(214, "秒杀已结束"),SECKILL_SUCCESS(215, "抢单成功"),SECKILL_FAIL(216, "抢单失败"),SECKILL_ILLEGAL(217, "请求不合法"),SECKILL_ORDER_SUCCESS(218, "下单成功"),COUPON_GET(220, "优惠券已经领取"),COUPON_LIMIT_GET(221, "优惠券已发放完毕"),;private Integer code;private String message;private ResultCodeEnum(Integer code, String message) {this.code = code;this.message = message;}
}

util下: 

AuthContextHolder :获取登录用户信息类 

package com.atguigu.gmall.common.util;//import com.baomidou.mybatisplus.core.toolkit.StringUtils;import org.springframework.util.StringUtils;import javax.servlet.http.HttpServletRequest;/*** 获取登录用户信息类*/
public class AuthContextHolder {/*** 获取当前登录用户id* @param request* @return*/public static String getUserId(HttpServletRequest request) {String userId = request.getHeader("userId");return StringUtils.isEmpty(userId) ? "" : userId;}/*** 获取当前未登录临时用户id* @param request* @return*/public static String getUserTempId(HttpServletRequest request) {String userTempId = request.getHeader("userTempId");return StringUtils.isEmpty(userTempId) ? "" : userTempId;}
}

 DateUtil:日期操作工具类

package com.atguigu.gmall.common.util;import org.apache.commons.lang.time.DateUtils;import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;/*** 日期操作工具类*/
public class DateUtil {private static final String dateFormat = "yyyy-MM-dd";/*** 获取两个时间差 单位:秒* @param date1* @param date2* @return*/public Long getTimeSubtract(Date date1, Date date2) {return (date1.getTime() - date2.getTime()) / 1000;}/*** 格式化日期** @param date* @return*/public static String formatDate(Date date) {SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);return sdf.format(date);}/*** 截取比较断两个日期对象的field处的值 。* 如果第一个日期小于、等于、大于第二个,则对应返回负整数、0、正整数** @param date1 第一个日期对象,非null* @param date2 第二个日期对象,非null* @param field Calendar中的阈值*              <p>*              date1 > date2  返回:1*              date1 = date2  返回:0*              date1 < date2  返回:-1*/public static int truncatedCompareTo(final Date date1, final Date date2, final int field) {return DateUtils.truncatedCompareTo(date1, date2, field);}/*** 比对时间大小** @param beginDate* @param endDate* @return*/public static boolean dateCompare(Date beginDate, Date endDate) {// endDate > beginDateif (DateUtil.truncatedCompareTo(beginDate, endDate, Calendar.SECOND) == 1) {return false;}// beginDate  <= endDatereturn true;}
}

HttpClientUtil:HttpClient类   http客户端类    微信: 

package com.atguigu.gmall.common.util;import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;/*** HttpClient类 微信:**/
public class HttpClientUtil {public static String doGet(String url)   {// 创建Httpclient对象CloseableHttpClient httpclient = HttpClients.createDefault();// 创建http GET请求HttpGet httpGet = new HttpGet(url);CloseableHttpResponse response = null;try {// 执行请求response = httpclient.execute(httpGet);// 判断返回状态是否为200if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {HttpEntity entity = response.getEntity();String result = EntityUtils.toString(entity, "UTF-8");EntityUtils.consume(entity);httpclient.close();return result;}httpclient.close();}catch (IOException e){e.printStackTrace();return null;}return  null;}public static void download(String url,String fileName)   {// 创建Httpclient对象CloseableHttpClient httpclient = HttpClients.createDefault();// 创建http GET请求HttpGet httpGet = new HttpGet(url);CloseableHttpResponse response = null;try {// 执行请求response = httpclient.execute(httpGet);// 判断返回状态是否为200if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {HttpEntity entity = response.getEntity();// String result = EntityUtils.toString(entity, "UTF-8");byte[] bytes = EntityUtils.toByteArray(entity);File file =new File(fileName);//  InputStream in = entity.getContent();FileOutputStream fout = new FileOutputStream(file);fout.write(bytes);EntityUtils.consume(entity);httpclient.close();fout.flush();fout.close();return  ;}httpclient.close();}catch (IOException e){e.printStackTrace();return  ;}return   ;}
}

IpUtil :获取ip地址 

package com.atguigu.gmall.common.util;import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;/*** 获取ip地址*/
public class IpUtil {public static String getIpAddress(HttpServletRequest request) {String ipAddress = null;try {ipAddress = request.getHeader("x-forwarded-for");if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("WL-Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getRemoteAddr();if (ipAddress.equals("127.0.0.1")) {// 根据网卡取本机配置的IPInetAddress inet = null;try {inet = InetAddress.getLocalHost();} catch (UnknownHostException e) {e.printStackTrace();}ipAddress = inet.getHostAddress();}}// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()// = 15if (ipAddress.indexOf(",") > 0) {ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));}}} catch (Exception e) {ipAddress="";}// ipAddress = this.getRequest().getRemoteAddr();return ipAddress;}// 网关中获取Ip地址public static String getGatwayIpAddress(ServerHttpRequest request) {HttpHeaders headers = request.getHeaders();String ip = headers.getFirst("x-forwarded-for");if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {// 多次反向代理后会有多个ip值,第一个ip才是真实ipif (ip.indexOf(",") != -1) {ip = ip.split(",")[0];}}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = headers.getFirst("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = headers.getFirst("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = headers.getFirst("HTTP_CLIENT_IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = headers.getFirst("HTTP_X_FORWARDED_FOR");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = headers.getFirst("X-Real-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddress().getAddress().getHostAddress();}return ip;}
}

MD5 :通过MD5给字符串加密的工具类 

package com.atguigu.gmall.common.util;import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;public final class MD5 {public static String encrypt(String strSrc) {try {char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8','9', 'a', 'b', 'c', 'd', 'e', 'f' };byte[] bytes = strSrc.getBytes();MessageDigest md = MessageDigest.getInstance("MD5");md.update(bytes);bytes = md.digest();int j = bytes.length;char[] chars = new char[j * 2];int k = 0;for (int i = 0; i < bytes.length; i++) {byte b = bytes[i];chars[k++] = hexChars[b >>> 4 & 0xf];chars[k++] = hexChars[b & 0xf];}return new String(chars);} catch (NoSuchAlgorithmException e) {e.printStackTrace();throw new RuntimeException("MD5加密出错!!+" + e);}}}

2.2搭建service-util模块

点击common,选择New–>Module,搭建过程同common-util

修改pom:

引入依赖:

<dependencies><dependency><groupId>com.atguigu.gmall</groupId><artifactId>common-util</artifactId><version>1.0-SNAPSHOT</version></dependency><!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- spring2.X集成redis所需common-pool2--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><!-- redisson 分布式锁--><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId></dependency><!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><scope>provided</scope></dependency></dependencies>

 添加service-util公共类

 GmallCache:注解

package com.atguigu.gmall.common.cache;import java.lang.annotation.*;/*** @author atguigu-mqx*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface GmallCache {//  定义一个数据 sku:skuId//  目的用这个前缀要想组成 缓存的key!String prefix() default "cache:";}

GmallCacheAspect: 

package com.atguigu.gmall.common.cache;import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.constant.RedisConst;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import java.util.Arrays;
import java.util.concurrent.TimeUnit;/*** @author atguigu-mqx*/
@Component
@Aspect
public class GmallCacheAspect {@Autowiredprivate RedissonClient redissonClient;@Autowiredprivate RedisTemplate redisTemplate;//  定义一个环绕通知!@SneakyThrows@Around("@annotation(com.atguigu.gmall.common.cache.GmallCache)")public Object gmallCacheAspectMethod(ProceedingJoinPoint point){//  定义一个对象Object obj = new Object();/*业务逻辑!1. 必须先知道这个注解在哪些方法 || 必须要获取到方法上的注解2. 获取到注解上的前缀3. 必须要组成一个缓存的key!4. 可以通过这个key 获取缓存的数据true:直接返回!false:分布式锁业务逻辑!*/MethodSignature methodSignature = (MethodSignature) point.getSignature();GmallCache gmallCache = methodSignature.getMethod().getAnnotation(GmallCache.class);//   获取到注解上的前缀String prefix = gmallCache.prefix();//  组成缓存的key! 获取方法传递的参数String key = prefix+ Arrays.asList(point.getArgs()).toString();try {//  可以通过这个key 获取缓存的数据obj = this.getRedisData(key,methodSignature);if (obj==null){//  分布式业务逻辑//  设置分布式锁,进入数据库进行查询数据!RLock lock = redissonClient.getLock(key + ":lock");//  调用trylock方法boolean result = lock.tryLock(RedisConst.SKULOCK_EXPIRE_PX1, RedisConst.SKULOCK_EXPIRE_PX2, TimeUnit.SECONDS);//  判断if(result){try {//  执行业务逻辑:直接从数据库获取数据//  这个注解 @GmallCache 有可能在 BaseCategoryView getCategoryName , List<SpuSaleAttr> getSpuSaleAttrListById ....obj = point.proceed(point.getArgs());//  防止缓存穿透if (obj==null){Object object = new Object();//  将缓存的数据变为 Json 的 字符串this.redisTemplate.opsForValue().set(key, JSON.toJSONString(object),RedisConst.SKUKEY_TEMPORARY_TIMEOUT,TimeUnit.SECONDS);return object;}//  将缓存的数据变为 Json 的 字符串this.redisTemplate.opsForValue().set(key, JSON.toJSONString(obj),RedisConst.SKUKEY_TIMEOUT,TimeUnit.SECONDS);return obj;}finally {//  解锁lock.unlock();}}else {//  没有获取到try {Thread.sleep(100);return gmallCacheAspectMethod(point);} catch (InterruptedException e) {e.printStackTrace();}}}else {//  直接从缓存获取的数据!return obj;}} catch (Throwable throwable) {throwable.printStackTrace();}//  数据库兜底!return point.proceed(point.getArgs());}/*** 从缓存中获取数据!* @param key* @return*/private Object getRedisData(String key,MethodSignature methodSignature) {//  在向缓存存储数据的时候,将数据变为Json 字符串了!//  通过这个key 获取到缓存的valueString strJson = (String) this.redisTemplate.opsForValue().get(key);//  判断if(!StringUtils.isEmpty(strJson)){//  将字符串转换为对应的数据类型!return JSON.parseObject(strJson,methodSignature.getReturnType());}return null;}}

MybatisPlusConfig :MybatisPlus配置类 

package com.atguigu.gmall.common.config;import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;/*** MybatisPlus配置类**/
@EnableTransactionManagement
@Configuration
@MapperScan("com.atguigu.gmall.*.mapper")
public class MybatisPlusConfig {/*** 分页插件*/@Beanpublic PaginationInterceptor paginationInterceptor() {PaginationInterceptor paginationInterceptor = new PaginationInterceptor();// paginationInterceptor.setLimit(你的最大单页限制数量,默认 500 条,小于 0 如 -1 不受限制);return paginationInterceptor;}}

RedisConfig :Redis配置类,序列化

package com.atguigu.gmall.common.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
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.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import java.lang.reflect.Method;
import java.time.Duration;/*** Redis配置类*/
@Configuration
@EnableCaching
public class RedisConfig {// 声明模板/*ref = 表示引用value = 具体的值<bean class="org.springframework.data.redis.core.RedisTemplate" ><property name="defaultSerializer" ref = ""></bean>*/@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();//  设置redis的连接池工厂。redisTemplate.setConnectionFactory(redisConnectionFactory);//  设置序列化的。Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(objectMapper);//  将Redis 中 string ,hash 数据类型,自动序列化!redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);//  设置数据类型是Hash 的 序列化!redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}}

RedissonConfig:redisson配置信息

package com.atguigu.gmall.common.config;import lombok.Data;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;/*** redisson配置信息*/
@Data
@Configuration
@ConfigurationProperties("spring.redis")
public class RedissonConfig {private String host;private String addresses;private String password;private String port;private int timeout = 3000;private int connectionPoolSize = 64;private int connectionMinimumIdleSize=10;private int pingConnectionInterval = 60000;private static String ADDRESS_PREFIX = "redis://";/*** 自动装配**/@BeanRedissonClient redissonSingle() {Config config = new Config();if(StringUtils.isEmpty(host)){throw new RuntimeException("host is  empty");}SingleServerConfig serverConfig = config.useSingleServer()//redis://127.0.0.1:7181.setAddress(ADDRESS_PREFIX + this.host + ":" + port).setTimeout(this.timeout).setPingConnectionInterval(pingConnectionInterval).setConnectionPoolSize(this.connectionPoolSize).setConnectionMinimumIdleSize(this.connectionMinimumIdleSize);if(!StringUtils.isEmpty(this.password)) {serverConfig.setPassword(this.password);}// RedissonClient redisson = Redisson.create(config);return Redisson.create(config);}
}

Swagger2Config :

package com.atguigu.gmall.common.config;import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.util.ArrayList;
import java.util.List;/*** Swagger2配置信息*/
@Configuration
@EnableSwagger2
public class Swagger2Config {@Beanpublic Docket webApiConfig(){//添加head参数startList<Parameter> pars = new ArrayList<>();ParameterBuilder tokenPar = new ParameterBuilder();tokenPar.name("userId").description("用户ID").defaultValue("1").modelRef(new ModelRef("string")).parameterType("header").required(false).build();pars.add(tokenPar.build());ParameterBuilder tmpPar = new ParameterBuilder();tmpPar.name("userTempId").description("临时用户ID").defaultValue("1").modelRef(new ModelRef("string")).parameterType("header").required(false).build();pars.add(tmpPar.build());//添加head参数endreturn new Docket(DocumentationType.SWAGGER_2).groupName("webApi").apiInfo(webApiInfo()).select()//过滤掉admin路径下的所有页面.paths(Predicates.and(PathSelectors.regex("/api/.*")))//过滤掉所有error或error.*页面//.paths(Predicates.not(PathSelectors.regex("/error.*"))).build().globalOperationParameters(pars);}@Beanpublic Docket adminApiConfig(){return new Docket(DocumentationType.SWAGGER_2).groupName("adminApi").apiInfo(adminApiInfo()).select()//只显示admin路径下的页面.paths(Predicates.and(PathSelectors.regex("/admin/.*"))).build();}private ApiInfo webApiInfo(){return new ApiInfoBuilder().title("网站-API文档").description("本文档描述了网站微服务接口定义").version("1.0").contact(new Contact("Helen", "http://atguigu.com", "55317332@qq.com")).build();}private ApiInfo adminApiInfo(){return new ApiInfoBuilder().title("后台管理系统-API文档").description("本文档描述了后台管理系统微服务接口定义").version("1.0").contact(new Contact("Helen", "http://atguigu.com", "55317332@qq.com")).build();}}

RedisConst:Redis常量配置类 

package com.atguigu.gmall.common.constant;/*** Redis常量配置类* set name admin*/
public class RedisConst {public static final String SKUKEY_PREFIX = "sku:";public static final String SKUKEY_SUFFIX = ":info";//单位:秒public static final long SKUKEY_TIMEOUT = 24 * 60 * 60;// 定义变量,记录空对象的缓存过期时间public static final long SKUKEY_TEMPORARY_TIMEOUT = 10 * 60;//单位:秒 尝试获取锁的最大等待时间public static final long SKULOCK_EXPIRE_PX1 = 1;//单位:秒 锁的持有时间public static final long SKULOCK_EXPIRE_PX2 = 1;public static final String SKULOCK_SUFFIX = ":lock";public static final String USER_KEY_PREFIX = "user:";public static final String USER_CART_KEY_SUFFIX = ":cart";public static final long USER_CART_EXPIRE = 60 * 60 * 24 * 30;//用户登录public static final String USER_LOGIN_KEY_PREFIX = "user:login:";//    public static final String userinfoKey_suffix = ":info";public static final int USERKEY_TIMEOUT = 60 * 60 * 24 * 7;//秒杀商品前缀public static final String SECKILL_GOODS = "seckill:goods";public static final String SECKILL_ORDERS = "seckill:orders";public static final String SECKILL_ORDERS_USERS = "seckill:orders:users";public static final String SECKILL_STOCK_PREFIX = "seckill:stock:";public static final String SECKILL_USER = "seckill:user:";//用户锁定时间 单位:秒public static final int SECKILL__TIMEOUT = 60 * 60 * 1;}

GlobalExceptionHandler :全局异常处理类

package com.atguigu.gmall.common.handler;import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;/*** 全局异常处理类**/
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)@ResponseBodypublic Result error(Exception e){e.printStackTrace();return Result.fail();}/*** 自定义异常处理方法* @param e* @return*/@ExceptionHandler(GmallException.class)@ResponseBodypublic Result error(GmallException e){return Result.fail(e.getMessage());}
}

(3)搭建model模块

点击gmall-parent 父工程 选择module

导入实体类:给的资料中,搭建过程同common父模块

不写就是jar,写了形象一点 

引入依赖:

<dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><scope>provided </scope></dependency><!--swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><scope>provided </scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId><scope>provided </scope></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId><scope>provided </scope></dependency></dependencies>

引入实体类:

BaseEntity:是一个基础类

package com.atguigu.gmall.model.base;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.io.Serializable;
import java.util.Date;@Data
public class BaseEntity implements Serializable {@ApiModelProperty(value = "id")@TableId(type = IdType.AUTO)private Long id;@ApiModelProperty(value = "创建时间")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")@TableField("create_time")private Date createTime;@ApiModelProperty(value = "更新时间")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")@TableField("update_time")private Date updateTime;@ApiModelProperty(value = "逻辑删除(1:已删除,0:未删除)")@JsonIgnore@TableLogic@TableField("is_deleted")private Integer isDeleted;
}

所有的实体类都继承了这个类:

(4)搭建service父模块

serviceservice模块父节点

service-product:商品服务模块

...

搭建过程同common父模块

他是父工程,删除src 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/31955.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

程序猿大战Python——面向对象——继承基础

定义类的几种语法 目标&#xff1a;了解定义类的标准语法。 我们知道&#xff0c;可以使用class关键字定义类。 在类的使用中&#xff0c;定义方式有三种&#xff1a; &#xff08;1&#xff09;【类名】 &#xff08;2&#xff09;【类名()】 &#xff08;3&#xff09;【…

MySQL表的增删改查初阶(下篇)

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

在线二维码解码器:将二维码转换成网址链接

在当今数字化时代&#xff0c;二维码&#xff08;QR码&#xff09;已成为一种便捷的信息传递工具。它不仅可以存储大量数据&#xff0c;还能快速分享信息。然而&#xff0c;有时我们需要将二维码中的内容转换为网址链接&#xff0c;以便在浏览器中直接访问。小编将详细介绍如何…

2024头歌数据库期末综合(部分题)

目录 第7关&#xff1a;数据查询三 任务描述 知识补充 答案 第8关&#xff1a;数据查询四 任务描述 知识补充 答案 本篇博客声明&#xff1a;所有题的答案不在一起&#xff0c;可以去作者博客专栏寻找其它文章。 第7关&#xff1a;数据查询三 任务描述 本关任务&#x…

[C++ STL] list 详解

标题&#xff1a;[C STL] vector 详解 水墨不写bug 正文开始&#xff1a; 一、背景 C语言阶段&#xff0c;我们如果想要使用链表&#xff0c;需要自己手动实现一个链表。这是非常低效的做法&#xff0c;C中的STL中提供了链表“ list ”&#xff0c;我们在包含头文件 <list…

小米15系列将首发骁龙8 Gen4 SoC

高通已确认2024年骁龙峰会定于10月21日举行。在这次峰会中高通将推出其最新的移动芯片Snapdragon 8 Gen4 SoC。著名科技博主DigitalChatStation今天证实&#xff0c;骁龙8 Gen4将以小米15系列首次亮相。这意味着小米15系列将是第一款使用这款新旗舰处理器的手机。 这不是小米第…

C++ 编程技巧分享

侯捷 C 学习路径&#xff1a;面向对象的高级编程 -> STL库 -> C11新特性 -> cmake 1.1. C 与 C的区别 在C语言中&#xff0c;主要存在两大类内容&#xff0c;数据和处理数据的函数&#xff0c;二者彼此分离&#xff0c;是多对多的关系。不同的函数可以调用同一个数据…

小i机器人:总负债5.31亿,员工数量在减少,银行借款在增加,净利润已下降-362.68%

小i机器人:总负债5.31亿,员工数量在减少,银行借款在增加,总收入在增长,净利润已下降-362.68% 来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 目录 一、小i机器人公司介绍 二、小i机器人过去20年的发展历程和取得的成就 三、小i机器人的产品和技术架构 四、小i机器人…

[最新教程]Claude Sonnet 3.5注册方法详细步骤分享,新手小白收藏,文末免费送已注册的Claude账号

一.Claude sonnet 3.5大模型面世 6月21日&#xff0c;被称为“OpenAI 最强竞对”的大模型公司 Anthropic 发布了 Claude 3.5 系列模型中的第一个版本——Claude 3.5 Sonnet。 Anthropic 在官方博客中表示&#xff0c;Claude 3.5 Sonnet 提高了智能化的行业标准&#xff0c;在…

基于卷积神经网络的目标检测

卷积神经网络基础知识 1.什么是filter 通常一个6x6的灰度图像&#xff0c;构造一个3*3的矩阵&#xff0c;在卷积神经网络中称之为filter,对&#xff16;x6的图像进行卷积运算。 2.什么是padding 假设输出图像大小为nn与过滤器大小为ff&#xff0c;输出图像大小则为(n−f1)∗(…

【计算机毕业设计】204基于微信小程序疫情期间学生请假与销假系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

同一天里,两位大厂程序员猝死。。。

2024年&#xff0c;真的不是平静的一年。在几天前&#xff0c;IT行业接连发生了两件不幸的事情。 6月17日下午&#xff0c;东南亚电商公司Sh**ee位于北京的研发中心&#xff0c;一位负责研发的女员工突然在工位上晕倒。 同事们赶紧拨打了120&#xff0c;然而还是没能抢救过来&a…

【验证码识别】Yolov8实战某验3空间推理点选验证码,目标检测,语义分割,颜色分类。

【验证码识别】Yolov8实战某验3空间推理点选验证码&#xff0c;目标检测&#xff0c;语义分割&#xff0c;颜色分类。 文章目录 【验证码识别】Yolov8实战某验3空间推理点选验证码&#xff0c;目标检测&#xff0c;语义分割&#xff0c;颜色分类。声明1.空间推理验证码&#xf…

2024年全国青少信息素养大赛python编程复赛集训第四天编程题分享

整理资料不容易,感谢各位大佬给个点赞和分享吧,谢谢 大家如果不想阅读前边的比赛内容介绍,可以直接跳过:拉到底部看集训题目 (一)比赛内容: 【小学组】 1.了解输入与输出的概念,掌握使用基本输入输出和简单运算 为主的标准函数; 2.掌握注释的方法; 3.掌握基本数…

Studying-代码随想录训练营day17| 654.最大二叉树、617合并二叉树、700.二叉搜索树中的搜索、98.验证二叉树搜索树

第十七天&#xff0c;二叉树part05&#xff0c;进一步学习二叉树&#x1f4aa; 654.最大二叉树 文档讲解&#xff1a;代码随想录最大二叉树 视频讲解&#xff1a;手撕最大二叉树 题目&#xff1a; 学习&#xff1a;本题与利用中序和后序序列构造二叉树有相同之处。依据题目要求…

第五篇:构建与维护私有Docker Registry: 企业级实践指南

构建与维护私有Docker Registry: 企业级实践指南 1. 引言&#xff1a;解析私有Docker仓库的必要性 1.1 Docker Registry简介与私有化的好处 Docker Registry是一个用于存储和分发Docker镜像的系统。在Docker生态系统中&#xff0c;Registry扮演着至关重要的角色&#xff0c;为…

骨传导耳机值不值得入手?五款运动好物骨传导耳机推荐!

开放式耳机在如今社会中已经迅速成为大家购买耳机的新趋势&#xff0c;开放式蓝牙耳机作为骨传导耳机&#xff0c;深受喜欢听歌和热爱运动的人群欢迎。当大家谈到佩戴的稳固性时&#xff0c;后挂式骨传导耳机都会收到一致好评。对于热爱运动的人士而言&#xff0c;高品质的骨传…

A800显卡驱动安装(使用deb安装)

重新安装显卡驱动&#xff0c;查阅了资料将过程记录如下&#xff1a; 1.下载deb安装包 打开nvidia官网查找对应的驱动版本&#xff0c;A800所在的选项卡位置如图&#xff1a; 点击查找后下载得到的是nvidia-driver-local-repo-ubuntu2004-550.90.07_1.0-1_amd64.deb安装包 2.…

UDS服务——RequestDownload(0x34)

诊断协议那些事儿 诊断协议那些事儿专栏系列文章,本文介绍RequestDownload(0x34)—— 请求下载,用于给ECU下载数据的,最常见的应用就是在bootloader中,程序下载工具会发起请求下载,以完成ECU程序的升级。通过阅读本文,希望能对你有所帮助。 文章目录 诊断协议那些事儿…

linux如何部署前端项目和安装nginx

要在Linux上部署前端项目并安装Nginx&#xff0c;你可以按照以下步骤操作&#xff1a; 安装Nginx: sudo apt update sudo apt install nginx 启动Nginx服务: sudo systemctl start nginx 确保Nginx服务开机自启: sudo systemctl enable nginx 部署前端项目&#xff0c;假设前…