1.初始化版本,2.引入thirdpart模块,引入canteen模块,初始化菜品分类,spu

This commit is contained in:
zjf committed 2024-12-06 16:54:30 +08:00
commit aff77150d6
1595 files changed
+168833

No files matched your search

@@ -0,0 +1,78 @@
/*
* Copyright (c) 2018-2025, pjcloud All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: pjcloud
*/
package com.bsd.pjcloud.common.feign;
import com.bsd.pjcloud.common.feign.endpoint.FeignClientEndpoint;
import com.bsd.pjcloud.common.feign.interceptor.PjcloudFeignInnerRequestInterceptor;
import com.bsd.pjcloud.common.feign.interceptor.PjcloudFeignRequestCloseInterceptor;
import feign.Feign;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.PjcloudFeignClientsRegistrar;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* @author pjcloud
* @date 2020/2/8
* <p>
* feign 自动化配置
*/
@Configuration
@ConditionalOnClass(Feign.class)
@Import(PjcloudFeignClientsRegistrar.class)
@AutoConfigureAfter(EnableFeignClients.class)
public class PjcloudFeignAutoConfiguration {
/**
* feign actuator endpoint
* @param context
* @return FeignClientEndpoint
*/
@Bean
@ConditionalOnMissingBean
@ConditionalOnAvailableEndpoint
public FeignClientEndpoint feignClientEndpoint(ApplicationContext context) {
return new FeignClientEndpoint(context);
}
/**
* add http connection close header
*
* @return PjcloudFeignRequestCloseInterceptor
*/
@Bean
public PjcloudFeignRequestCloseInterceptor pigFeignRequestCloseInterceptor() {
return new PjcloudFeignRequestCloseInterceptor();
}
/**
* add inner request header
*
* @return PjcloudFeignInnerRequestInterceptor
*/
@Bean
public PjcloudFeignInnerRequestInterceptor pigFeignInnerRequestInterceptor() {
return new PjcloudFeignInnerRequestInterceptor();
}
}
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2018-2025, pjcloud All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: pjcloud
*/
package com.bsd.pjcloud.common.feign.annotation;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
/**
* @author pjcloud
* @date 2020-02-08
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@EnableFeignClients
public @interface EnablePjcloudFeignClients {
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
* declarations e.g.: {@code @ComponentScan("org.my.pkg")} instead of
* {@code @ComponentScan(basePackages="org.my.pkg")}.
* @return the array of 'basePackages'.
*/
String[] value() default {};
/**
* Base packages to scan for annotated components.
* <p>
* {@link #value()} is an alias for (and mutually exclusive with) this attribute.
* <p>
* Use {@link #basePackageClasses()} for a type-safe alternative to String-based
* package names.
* @return the array of 'basePackages'.
*/
@AliasFor(annotation = EnableFeignClients.class)
String[] basePackages() default { "com.bsd.pjcloud" };
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages to
* scan for annotated components. The package of each class specified will be scanned.
* <p>
* Consider creating a special no-op marker class or interface in each package that
* serves no purpose other than being referenced by this attribute.
* @return the array of 'basePackageClasses'.
*/
@AliasFor(annotation = EnableFeignClients.class)
Class<?>[] basePackageClasses() default {};
/**
* A custom <code>@Configuration</code> for all feign clients. Can contain override
* <code>@Bean</code> definition for the pieces that make up the client, for instance
* {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
*
* @see FeignClientsConfiguration for the defaults
*/
@AliasFor(annotation = EnableFeignClients.class)
Class<?>[] defaultConfiguration() default {};
/**
* List of classes annotated with @FeignClient. If not empty, disables classpath
* scanning.
* @return
*/
@AliasFor(annotation = EnableFeignClients.class)
Class<?>[] clients() default {};
}
@@ -0,0 +1,16 @@
package com.bsd.pjcloud.common.feign.annotation;
import java.lang.annotation.*;
/**
* 服务无token调用声明注解
* <p>
* 只有发起方没有 token 时候才需要添加此注解, @NoToken + @Inner
* <p>
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NoToken {
}
@@ -0,0 +1,127 @@
package com.bsd.pjcloud.common.feign.endpoint;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Feign client 端点
*
* @author L.cm
*/
@Endpoint(id = "feign")
public class FeignClientEndpoint implements SmartInitializingSingleton {
private final ApplicationContext context;
private final List<FeignClientInfo> clientList;
public FeignClientEndpoint(ApplicationContext context) {
this.context = context;
this.clientList = new ArrayList<>();
}
@ReadOperation
public List<FeignClientInfo> invoke() {
return clientList;
}
@Override
public void afterSingletonsInstantiated() {
clientList.addAll(getClientList(context));
}
private static List<FeignClientInfo> getClientList(ApplicationContext context) {
Map<String, Object> feignClientMap = context.getBeansWithAnnotation(FeignClient.class);
// 1. 解析注解
List<FeignClientInfo> feignClientInfoList = new ArrayList<>();
Set<Map.Entry<String, Object>> feignClientEntrySet = feignClientMap.entrySet();
for (Map.Entry<String, Object> feignClientEntry : feignClientEntrySet) {
String beanName = feignClientEntry.getKey();
Object feignClientBean = feignClientEntry.getValue();
if (feignClientBean == null) {
continue;
}
// 解析注解
Class<?> feignClientClass = feignClientBean.getClass();
FeignClient feignClientAnn = AnnotationUtils.findAnnotation(feignClientClass, FeignClient.class);
if (feignClientAnn == null) {
continue;
}
FeignClientInfo feignClientInfo = new FeignClientInfo();
feignClientInfo.setBeanName(beanName);
String serviceId = feignClientAnn.value();
String contextId = feignClientAnn.contextId();
String url = feignClientAnn.url();
String path = feignClientAnn.path();
feignClientInfo.setServiceId(serviceId);
feignClientInfo.setContextId(contextId);
feignClientInfo.setUrl(url);
feignClientInfo.setPath(path);
// 组装客户端信息
List<ClientInfo> clientInfoList = new ArrayList<>();
Class<?>[] interfaces = feignClientClass.getInterfaces();
for (Class<?> clientInterface : interfaces) {
Method[] methods = clientInterface.getDeclaredMethods();
for (Method method : methods) {
if (method.isDefault()) {
continue;
}
RequestMapping requestMapping = AnnotatedElementUtils.getMergedAnnotation(method,
RequestMapping.class);
if (requestMapping == null) {
continue;
}
clientInfoList.add(new ClientInfo(requestMapping.method(), requestMapping.value()));
}
}
feignClientInfo.setClientList(clientInfoList);
feignClientInfoList.add(feignClientInfo);
}
return feignClientInfoList;
}
@Getter
@Setter
public static class FeignClientInfo {
private String beanName;
private String serviceId;
private String contextId;
private String url;
private String path;
private List<ClientInfo> clientList;
}
@Getter
@AllArgsConstructor
public static class ClientInfo {
private final RequestMethod[] methods;
private final String[] mappings;
}
}
@@ -0,0 +1,36 @@
package com.bsd.pjcloud.common.feign.interceptor;
import com.bsd.pjcloud.common.core.constant.SecurityConstants;
import com.bsd.pjcloud.common.feign.annotation.NoToken;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.core.Ordered;
import java.lang.reflect.Method;
/**
* @author pjcloud
* @date 2024/6/1
*/
public class PjcloudFeignInnerRequestInterceptor implements RequestInterceptor, Ordered {
/**
* Called for every request. Add data using methods on the supplied
* {@link RequestTemplate}.
* @param template
*/
@Override
public void apply(RequestTemplate template) {
Method method = template.methodMetadata().method();
NoToken noToken = method.getAnnotation(NoToken.class);
if (noToken != null) {
template.header(SecurityConstants.FROM, SecurityConstants.FROM_IN);
}
}
@Override
public int getOrder() {
return Integer.MIN_VALUE;
}
}
@@ -0,0 +1,23 @@
package com.bsd.pjcloud.common.feign.interceptor;
import feign.RequestInterceptor;
import org.springframework.http.HttpHeaders;
/**
* @author pjcloud
* @date 2024/3/15
* <p>
* http connection close
*/
public class PjcloudFeignRequestCloseInterceptor implements RequestInterceptor {
/**
* set connection close
* @param template
*/
@Override
public void apply(feign.RequestTemplate template) {
template.header(HttpHeaders.CONNECTION, "close");
}
}
@@ -0,0 +1,274 @@
/*
* Copyright (c) 2018-2025, pjcloud All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: pjcloud
*/
package org.springframework.cloud.openfeign;
import lombok.Getter;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.context.annotation.ImportCandidates;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author L.cm
* @date 2020/2/8
* <p>
* feign 自动配置功能 from mica
*/
public class PjcloudFeignClientsRegistrar
implements ImportBeanDefinitionRegistrar, BeanClassLoaderAware, EnvironmentAware {
private final static String BASE_URL = "http://127.0.0.1:${server.port}${server.servlet.context-path}";
@Getter
private ClassLoader beanClassLoader;
@Getter
private Environment environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
registerFeignClients(registry);
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
private void registerFeignClients(BeanDefinitionRegistry registry) {
List<String> feignClients = new ArrayList<>();
// 支持 springboot 2.7 + 最新版本的配置方式
ImportCandidates.load(FeignClient.class, getBeanClassLoader()).forEach(feignClients::add);
// 如果 spring.factories 里为空
if (feignClients.isEmpty()) {
return;
}
for (String className : feignClients) {
try {
Class<?> clazz = beanClassLoader.loadClass(className);
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(clazz,
FeignClient.class);
if (attributes == null) {
continue;
}
// 如果是单体项目自动注入 & url 为空
Boolean isMicro = environment.getProperty("spring.cloud.nacos.discovery.enabled", Boolean.class, true);
// 如果已经存在该 bean,支持原生的 Feign
if (registry.containsBeanDefinition(className) && isMicro) {
continue;
}
registerClientConfiguration(registry, getClientName(attributes), className,
attributes.get("configuration"));
validate(attributes);
BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
definition.addPropertyValue("url", getUrl(attributes));
definition.addPropertyValue("path", getPath(attributes));
String name = getName(attributes);
definition.addPropertyValue("name", name);
// 兼容最新版本的 spring-cloud-openfeign,尚未发布
StringBuilder aliasBuilder = new StringBuilder(18);
if (attributes.containsKey("contextId")) {
String contextId = getContextId(attributes);
aliasBuilder.append(contextId);
definition.addPropertyValue("contextId", contextId);
} else {
aliasBuilder.append(name);
}
definition.addPropertyValue("type", className);
definition.addPropertyValue("dismiss404",
Boolean.parseBoolean(String.valueOf(attributes.get("dismiss404"))));
Object fallbackFactory = attributes.get("fallbackFactory");
if (fallbackFactory != null) {
definition.addPropertyValue("fallbackFactory", fallbackFactory instanceof Class ? fallbackFactory
: ClassUtils.resolveClassName(fallbackFactory.toString(), null));
}
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
// alias
String alias = aliasBuilder.append("FeignClient").toString();
// has a default, won't be null
boolean primary = (Boolean) attributes.get("primary");
beanDefinition.setPrimary(primary);
String qualifier = getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
new String[]{alias});
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
private void validate(Map<String, Object> attributes) {
AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes);
// This blows up if an aliased property is overspecified
FeignClientsRegistrar.validateFallback(annotation.getClass("fallback"));
FeignClientsRegistrar.validateFallbackFactory(annotation.getClass("fallbackFactory"));
}
private String getName(Map<String, Object> attributes) {
String name = (String) attributes.get("serviceId");
if (!StringUtils.hasText(name)) {
name = (String) attributes.get("name");
}
if (!StringUtils.hasText(name)) {
name = (String) attributes.get("value");
}
name = resolve(name);
return FeignClientsRegistrar.getName(name);
}
private String getContextId(Map<String, Object> attributes) {
String contextId = (String) attributes.get("contextId");
if (!StringUtils.hasText(contextId)) {
return getName(attributes);
}
contextId = resolve(contextId);
return FeignClientsRegistrar.getName(contextId);
}
private String resolve(String value) {
if (StringUtils.hasText(value)) {
return this.environment.resolvePlaceholders(value);
}
return value;
}
private String getUrl(Map<String, Object> attributes) {
// 如果是单体项目自动注入 & url 为空
Boolean isMicro = environment.getProperty("spring.cloud.nacos.discovery.enabled", Boolean.class, true);
if (isMicro) {
return null;
}
Object objUrl = attributes.get("url");
String url = "";
if (StringUtils.hasText(objUrl.toString())) {
url = resolve(objUrl.toString());
} else {
url = resolve(BASE_URL);
}
return FeignClientsRegistrar.getUrl(url);
}
private String getPath(Map<String, Object> attributes) {
String path = resolve((String) attributes.get("path"));
return FeignClientsRegistrar.getPath(path);
}
@Nullable
private String getQualifier(@Nullable Map<String, Object> client) {
if (client == null) {
return null;
}
String qualifier = (String) client.get("qualifier");
if (StringUtils.hasText(qualifier)) {
return qualifier;
}
return null;
}
@Nullable
private String getClientName(@Nullable Map<String, Object> client) {
if (client == null) {
return null;
}
String value = (String) client.get("contextId");
if (!StringUtils.hasText(value)) {
value = (String) client.get("value");
}
if (!StringUtils.hasText(value)) {
value = (String) client.get("name");
}
if (!StringUtils.hasText(value)) {
value = (String) client.get("serviceId");
}
if (StringUtils.hasText(value)) {
return value;
}
throw new IllegalStateException(
"Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName());
}
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),
builder.getBeanDefinition());
}
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object className,
Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(className);
builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),
builder.getBeanDefinition());
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}