当前位置: 首页 > news >正文

银川做淘宝网站的网站流量统计数据库设计

银川做淘宝网站的,网站流量统计数据库设计,wordpress目的,wordpress多价格插件一.简介 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的工具。它简化了基于 Spring 的应用程序的配置和部署过程#xff0c;提供了一种快速、便捷的方式来构建独立的、生产级别的 Spring 应用程序。 Spring Boot 的一些主要优点包括#xff1a; 1. 简化配置…一.简介 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的工具。它简化了基于 Spring 的应用程序的配置和部署过程提供了一种快速、便捷的方式来构建独立的、生产级别的 Spring 应用程序。 Spring Boot 的一些主要优点包括 1. 简化配置Spring Boot 提供了自动配置功能可以根据应用程序的依赖和环境自动配置 Spring 应用程序减少了繁琐的配置工作。 2. 内嵌式容器Spring Boot 内置了常用的 Web 容器如 Tomcat、Jetty 或 Undertow使得应用程序可以作为独立的应用程序运行而不需要外部的 Web 服务器。 3. 自动化管理Spring Boot 提供了许多自动化的管理功能如健康检查、指标收集、配置管理等使得应用程序的管理变得更加简单。 4. 微服务支持Spring Boot 提供了对微服务架构的良好支持可以轻松构建和部署微服务应用程序。 使用 Spring Boot 可以通过以下步骤 1. 创建一个 Spring Boot 项目你可以使用 Spring Initializrhttps://start.spring.io/来创建一个新的 Spring Boot 项目选择所需的依赖和项目设置。 2. 编写应用程序代码根据你的需求编写应用程序的业务逻辑和控制器可以使用 Spring Boot 提供的自动配置功能简化项目的配置。 3. 运行应用程序使用 Maven 或 Gradle 构建你的项目并运行生成的可执行 JAR 文件或 WAR 文件。 4. 部署应用程序将生成的可执行文件部署到服务器上Spring Boot 内置了常用的 Web 容器可以直接运行应用程序。 总之Spring Boot 是一个用于简化 Spring 应用程序开发和部署的工具它提供了许多便利的功能和特性使得开发者可以更加高效地构建和管理 Spring 应用程序。 Web 是什么web项目是什么web容器是什么 Web 是指World Wide Web万维网的简称它是由许多互联网服务器组成的一个庞大的信息系统。Web 通过使用超文本传输协议HTTP来传输数据并使用统一资源定位符URL来定位资源如网页、图片、视频等。Web 也使用超文本标记语言HTML等技术来创建和展示内容。 Web 项目是指基于 Web 技术开发的应用程序或服务。这些项目通常是通过 Web 浏览器进行访问和交互的可以提供各种功能如信息展示、数据交互、在线购物、社交网络等。Web 项目通常由前端页面、后端服务器和数据库等组成以实现用户与系统的交互和数据处理。 Web 容器是一个用于运行 Web 应用程序的服务器环境。它负责管理 Web 应用程序的生命周期处理 HTTP 请求和响应以及提供运行环境和支持。Web 容器还负责与 Web 服务器如 Apache、Nginx 等通信将请求转发给适当的 Web 应用程序并将处理后的响应返回给客户端。 常见的 Web 容器包括 Tomcat、Jetty、Undertow 等。这些容器提供了一个运行 Java Servlet、JavaServer PagesJSP和其他 Java Web 技术的环境。除了 Java 的 Web 容器之外还有许多其他语言和框架的 Web 容器比如 Node.js 的 Express 框架、Python 的 Django 框架等。 总的来说Web 项目是通过 Web 技术开发的应用程序而 Web 容器则是用于运行和管理这些 Web 项目的服务器环境。它们共同构成了 Web 应用程序的运行和交互环境。 二.Spring Boot 内容包括Json数据封装、日志记录、属性配置、MVC支持、在线文档、模板引擎、异常处理、AOP 处理、持久层集成等等。内容包括拦截器、监听器、缓存、安全认证、分词插件、消息队列等等。 FastJson Swagger2ThymeleafMyBatisRedisActiveMQShiroLucence 1.Spring Boot开发环境搭建和项目启动 要搭建 Spring Boot 的开发环境并启动一个项目你可以按照以下步骤进行 1. 确保你的开发环境中已经安装了 Java 开发工具包JDK。你可以从 Oracle 官网或者 OpenJDK 官网下载并安装适合你操作系统的 JDK 版本。 2. 选择一个集成开发环境IDE来编写和管理你的 Spring Boot 项目。常见的选择包括 IntelliJ IDEA、Eclipse 和 VS Code。确保你已经安装了你选择的 IDE。 3. 创建一个新的 Spring Boot 项目。你可以使用 Spring Initializrhttps://start.spring.io/来初始化一个新项目。在 Spring Initializr 网站上你可以选择项目的元数据、依赖和构建工具如 Maven 或 Gradle然后生成一个基本的 Spring Boot 项目结构。 4. 使用你的 IDE 打开新创建的项目。导入项目到你的 IDE 中确保项目结构被正确加载。 5. 编写你的应用程序代码。在 src/main/java 目录下创建你的应用程序主类并编写你的业务逻辑和控制器。 6. 运行你的 Spring Boot 项目。在 IDE 中你可以直接运行你的主类通常是一个带有 SpringBootApplication 注解的类或者使用 Maven 或 Gradle 命令来构建和运行你的项目。 7. 访问你的应用程序。一旦应用程序启动你可以在浏览器中访问 http://localhost:8080默认端口来查看你的应用程序运行情况。 这些步骤可以帮助你在本地搭建 Spring Boot 的开发环境并启动一个简单的项目。一旦你熟悉了这些基本步骤你可以继续学习如何配置数据库、编写 RESTful 服务、添加前端界面等更多高级的开发任务。 2.Spring Boot返回Json数据及数据封装 在 Spring Boot 中你可以很容易地返回 JSON 数据并进行数据封装。通常情况下你可以使用 Spring MVC 中的 RestController 注解来标记你的控制器类这样它就能够返回 JSON 数据了。下面是一个简单的例子演示如何在 Spring Boot 中返回 JSON 数据并进行数据封装。 RestController Target({ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) Documented Controller ResponseBody public interface RestController {     String value() default ; } RestController 注解包含了原来的 Controller 和 ResponseBody 注解使用过 Spring 的朋友对 Controller 注解已经非常了解了这里不再赘述 ResponseBody 注解是将返回的数据结构转换为 Json 格式。所以在默认情况下使用了 RestController 注解即可将返回的数据结构转换成 Json 格式Spring Boot 中默认使用的 Json 解析技术框架是 jackson。我们点开 pom.xml 中的 spring-boot-starter-web 依赖。原文链接https://blog.csdn.net/cuiqwei/article/details/118188540 新建一个 jackson 的配置类想null变成“” import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class JacksonConfig {     Bean     public ObjectMapper objectMapper() {         ObjectMapper objectMapper new ObjectMapper();         objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);         objectMapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);         return objectMapper;     } } 在这个示例中我们创建了一个名为 JacksonConfig 的配置类并在其中定义了一个名为 objectMapper 的 Bean 方法。在该方法中我们创建了一个新的 ObjectMapper 实例并进行了两项配置 1. 我们使用 setSerializationInclusion 方法将 null 值序列化为非空字符串。 2. 我们使用 configure 方法禁止序列化器写入 null map 值这样可以确保在序列化过程中将 null 值转换为空字符串。 通过这个配置类我们告诉 Spring Boot 在启动时使用我们自定义的 ObjectMapper 实例从而改变了 Jackson 序列化 null 值的默认行为。 在你的 Spring Boot 应用程序中只需将这个配置类放在合适的包路径下Spring Boot 就会自动扫描并应用这个配置。这样在你的应用程序中任何使用 Jackson 进行序列化的地方都会遵循你在这个配置类中定义的规则将 null 值序列化为空字符串。 Jackson 和 FastJson Jackson 和 FastJson 都是流行的 Java JSON 处理库它们都提供了序列化和反序列化 JSON 数据的功能。下面是它们之间的一些对比 性能FastJson 在处理速度上通常比 Jackson 更快。这是因为 FastJson 设计时就专注于性能采用了一些优化策略包括基于 ASM 的动态字节码生成来提高性能。 灵活性Jackson 提供了更多的配置选项和定制能力可以更灵活地满足不同的需求。FastJson 也提供了一些配置选项但相对来说没有那么多。 社区支持Jackson 是一个非常成熟和广泛使用的库在社区支持和文档方面更加丰富。FastJson 也有相当数量的用户但在社区支持和文档方面可能略逊一筹。 jackson 和 fastJson 两者冲突吗如何全局只使用fastjson 在一个项目中同时使用 Jackson 和 FastJson 可能会导致冲突和不一致的行为因为它们都是用来处理 JSON 的库它们可能会对 JSON 的序列化和反序列化产生不同的结果。因此最好的做法是在项目中只使用其中一个库。 如果你想在项目中全局只使用 FastJson你可以按照以下步骤进行配置 1. 移除项目中的 Jackson 相关依赖首先你需要将项目中所有的 Jackson 相关依赖移除包括任何与 Spring Boot 集成的 Jackson 相关依赖。你可以在 Maven 或 Gradle 的配置文件中将这些依赖移除。 2. 添加 FastJson 依赖在项目中添加 FastJson 的依赖你可以使用 Maven 或 Gradle 来添加相应的依赖。 3. 配置 Spring Boot 使用 FastJson如果你在使用 Spring Boot你可以配置 Spring Boot 使用 FastJson 作为默认的 JSON 处理库。以下是一个示例配置 import com.alibaba.fastjson.support.config.FastJsonConfig; import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; Configuration public class WebMvcConfig implements WebMvcConfigurer {     Override     public void configureMessageConverters(ListHttpMessageConverter? converters) {         // 创建FastJson消息转换器         FastJsonHttpMessageConverter converter new FastJsonHttpMessageConverter();         FastJsonConfig config new FastJsonConfig();         // 配置FastJson的行为例如是否输出null值等         // config.set...         converter.setFastJsonConfig(config);         converters.add(0, converter);     } }  备注 Bean和Configuration 那么什么时候应该使用Bean注解呢通常情况下当你需要将一个特定的对象注册为Spring应用上下文中的bean时你可以使用Bean注解。这在很多情况下非常有用比如创建自定义的bean、集成第三方库、或者注册一些Spring框架中没有默认注册的组件等。 总的来说Bean注解用于向Spring容器注册bean而Configuration注解用于标识一个类为配置类告诉Spring在启动时要处理这个类中的bean定义。 3.统一异常处理 通常情况下我们会使用统一异常处理来确保在出现异常错误时也返回统一的格式。在 Spring 框架中可以通过 ControllerAdvice 和 ExceptionHandler 注解来实现统一异常处理。 以下是一个简单的示例展示了如何使用统一异常处理来返回统一的 JSON 格式 ControllerAdvice public class GlobalExceptionHandler {ExceptionHandler(Exception.class)ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)ResponseBodypublic ApiResponse? handleException(HttpServletRequest request, Exception ex) {MapString, String headers getHeadersFromRequest(request);return ApiResponse.error(500, Internal Server Error, headers);}private MapString, String getHeadersFromRequest(HttpServletRequest request) {// 从请求中获取头部信息的逻辑// 这里只是一个示例实际情况可能会根据项目需求进行定制MapString, String headers new HashMap();EnumerationString headerNames request.getHeaderNames();while (headerNames.hasMoreElements()) {String headerName headerNames.nextElement();String headerValue request.getHeader(headerName);headers.put(headerName, headerValue);}return headers;} }AOP来打印方法的入参、出参以及请求头信息等 当使用AOP来打印方法的入参、出参以及请求头信息时你可以使用Around注解来实现。在环绕通知中你可以获取方法的参数、返回值以及请求头信息并在方法执行前后打印这些信息。同时你也可以使用AfterThrowing注解来处理异常信息以便在异常发生时进行日志记录。  Aspect Component public class LoggingAspect {     private static final Logger logger LoggerFactory.getLogger(LoggingAspect.class);     Around(execution(* com.example.*.*(..)))     public Object logMethodCall(ProceedingJoinPoint joinPoint) throws Throwable {         String methodName joinPoint.getSignature().toShortString();         String requestId UUID.randomUUID().toString(); // 生成请求ID         ServletRequestAttributes attributes (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();         HttpServletRequest request attributes.getRequest();         // 打印请求头信息         logger.info(Request Headers: {}, Collections.list(request.getHeaderNames()));         // 打印方法入参         Object[] args joinPoint.getArgs();         logger.info(Method {} called with arguments: {}, methodName, Arrays.toString(args));         // 执行目标方法         Object result;         try {             result joinPoint.proceed();         } catch (Throwable e) {             // 在异常发生时打印异常信息             logger.error(Method {} threw an exception. Request ID: {}, methodName, requestId, e);             throw e;         }         // 打印方法出参         logger.info(Method {} returned with result: {}, methodName, result);         return result;     } } SLF4J、Log4j 和 Logback SLF4J 提供了统一的日志接口使得开发者可以更加灵活地选择日志实现Log4j 是一个成熟的日志框架拥有丰富的功能和广泛的应用Logback 是对 Log4j 的改进提供了更高的性能和更灵活的配置选项。在选择日志框架时可以根据项目的具体需求和团队的偏好来进行选择。  备注1.【强制】应用中不可直接使用日志系统Log4j、Logback中的API而应依赖使用日志框架SLF4J中的API使用门面模式的日志框架有利于维护和各个类的日志处理方式统一。 configuration!-- Define properties for dynamic values --property nameappName valueMyApp /property nameappInstanceId value${APP_INSTANCE_ID:-Instance1} /property namelogPath value/path/to/logs/ /property namelogFileName value${appName}-${appInstanceId} /property namelogLevel valueINFO /property namemaxLogFileSize value10MB /property namemaxHistory value30 /!-- Logback configuration --!-- Console Appender --appender nameSTDOUT classch.qos.logback.core.ConsoleAppenderencoderpattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/pattern/encoder/appender!-- File Appender --appender nameFILE classch.qos.logback.core.rolling.RollingFileAppenderfile${logPath}/${logFileName}.log/fileencoderpattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/pattern/encoderrollingPolicy classch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicyfileNamePattern${logPath}/${logFileName}.%d{yyyy-MM-dd}.%i.log.zip/fileNamePatternmaxFileSize${maxLogFileSize}/maxFileSizemaxHistory${maxHistory}/maxHistorytotalSizeCap1GB/totalSizeCap/rollingPolicy/appender!-- Root Logger --root level${logLevel}appender-ref refSTDOUT /appender-ref refFILE //root/configuration 1-格式:我们来看一下这个定义的含义首先定义一个格式命名为 “thread”该格式中 %date 表示日期%thread 表示线程名%-5level 表示级别从左显示5个字符宽度%logger{36} 表示 logger 名字最长36个字符%msg 表示日志消息%n 是换行符。原文链接https://blog.csdn.net/cuiqwei/article/details/118188540 2-日志存储的路径必须要是绝对路径。 3-使用 定义一个名为 “FILE” 的文件配置主要是配置日志文件保存的时间、单个日志文件存储的大小、以及文件保存的路径和日志的输出格式。 4-定义日志输出级别。ERROR、WARN、INFO、DEBUG。 5-在 logback.xml 中可以通过配置 AsyncAppender 来实现异步日志记录。AsyncAppender 接收日志事件并将其放入一个队列中然后由后台线程异步处理这些日志事件最终输出到相应的目的地如控制台、文件等。这种方式可以避免日志记录操作对应用程序性能的影响。 4.Spring Boot中的项目属性配置 在 Spring Boot 项目中项目属性配置是通过 application.properties 或 application.yml 文件来实现的。这些配置文件用于定义应用程序的属性、环境变量、数据库连接信息、日志配置等 1. 多环境配置 可以使用不同的配置文件来支持不同的环境例如 application-dev.properties、application-prod.properties、application-dev.yml、application-prod.yml 等。Spring Boot 会根据当前的环境自动加载相应的配置文件。 2. 外部化配置 除了 application.properties 和 application.yml 文件外Spring Boot 还支持外部化配置可以通过环境变量、命令行参数、JNDI、系统属性等来配置应用程序属性。 3. 配置优先级--配置失效的时候进行排查 Spring Boot 的属性配置有优先级顺序从高到低依次为命令行参数 Java 系统属性 操作系统环境变量 application.properties 或 application.yml 文件。 6. 自定义属性 除了 Spring Boot 内置的属性外还可以自定义属性并在代码中使用 Value 注解或者 ConfigurationProperties 注解来注入属性值。 7. 使用配置属性 在代码中可以通过 Value(${property.key}) 注解或者 ConfigurationProperties 注解来读取配置属性的值例如 Value(${spring.datasource.url}) private String dbUrl; 5.Spring Boot中的MVC支持 Spring Boot中的MVCModel-View-Controller您可以使用注解来定义控制器、请求映射和其他MVC相关的组件同时也能够利用自动配置来简化配置过程。以下是Spring Boot中MVC支持的一些关键特性和组件 1. 自动配置: Spring Boot提供了自动配置功能可以根据项目的依赖和配置自动配置Spring MVC所需的组件包括视图解析器、消息转换器、异常处理等。 2. 注解驱动的开发: Spring Boot鼓励使用注解来定义控制器、请求映射、请求参数绑定等使得开发过程更加简洁和高效。 3. RESTful支持: Spring Boot提供了对RESTful风格的支持包括对RestController和RequestBody注解的自动配置和支持使得构建RESTful API更加便捷。备注RESTful的设计原则是基于HTTP协议通过使用不同的HTTP方法例如GET、POST、PUT、DELETE等来实现对资源的操作 4. 视图解析: Spring Boot支持多种视图解析器包括Thymeleaf、FreeMarker、JSP等同时也支持静态资源的访问和处理。 5. 全局异常处理: Spring Boot提供了全局异常处理机制可以通过ControllerAdvice注解来定义全局异常处理器统一处理应用程序中的异常情况。 6. 数据绑定和校验: Spring Boot支持数据绑定和校验可以通过Valid注解和BindingResult对象来实现请求参数的校验和错误处理。 7. 拦截器: Spring Boot允许您定义拦截器来处理请求前后的逻辑例如日志记录、权限验证等。 总之Spring Boot提供了强大的MVC支持使得开发Web应用程序更加简单、灵活和高效。通过利用自动配置和注解驱动的开发开发者能够快速构建出功能丰富的Web应用程序。 注解RestController、 RequestMapping、PathVariable、RequestParam 以及 RequestBody 1. RestController这个注解用于标记一个类表示该类是一个RESTful风格的控制器Controller。在Spring Boot中使用RestController注解相当于同时使用Controller和ResponseBody两个注解表示该类中的方法返回的是数据而不是视图。 2. RequestMapping这个注解用于映射HTTP请求到控制器的处理方法。它可以用于类级别和方法级别用于指定URL路径和HTTP请求方法以及其他请求参数。在方法级别可以进一步指定具体的路径和请求方法。http://localhost:8080/user?id1  3. PathVariable这个注解用于从URL中获取路径参数例如/users/{id}中的id。通过在方法参数上添加PathVariable注解可以将URL中的路径参数映射到方法的参数上。http://localhost:8080/user/{id} 4. RequestParam这个注解用于从请求中获取查询参数例如/users?id123中的id。通过在方法参数上添加RequestParam注解可以将请求中的查询参数映射到方法的参数上。 5. RequestBody这个注解用于将HTTP请求的body部分映射到方法参数上通常用于接收JSON或XML格式的请求体。在处理POST请求时可以使用RequestBody注解将请求体中的数据映射到方法参数上。 这些注解是构建RESTful API时常用的注解在Spring Boot中使用它们可以简化对URL路径、请求参数和请求体的处理使得开发RESTful服务更加便捷和高效。 6.Spring Boot集成 Swagger2 展现在线接口文档 在Spring Boot中您可以使用Swagger2来生成并展示在线的接口文档。Swagger2是一个用于设计、构建、记录和使用RESTful API的工具。它可以通过注解来描述API的信息并生成交互式的API文档方便开发者查看和测试接口。 以下是集成Swagger2以展现在线接口文档的基本步骤 1. 添加Swagger2依赖在pom.xml文件中添加Swagger2的依赖。 2. 配置Swagger2创建一个Swagger配置类用于配置Swagger的基本信息和扫描的包路径。例如 Configuration EnableSwagger2 public class SwaggerConfig {Beanpublic Docket api() {return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.basePackage(com.example.controllers)).paths(PathSelectors.any()).build();} } 3. 启动应用程序启动Spring Boot应用程序后访问http://localhost:8080/swagger-ui.html即可查看生成的在线API文档。 通过以上步骤您就可以将Swagger2集成到Spring Boot应用程序中以展现在线的接口文档。在生成的文档中您可以查看API的详细信息、请求参数、响应数据等并且还可以在文档中进行接口的测试。 7.Spring Boot集成Thymeleaf模板引擎 略 8.Spring Boot中的全局异常处理 在Spring Boot中您可以通过使用ControllerAdvice注解来实现全局异常处理。这使得您可以集中处理应用程序中抛出的异常并统一返回自定义的错误信息或错误页面。 以下是一个简单的例子展示了如何在Spring Boot中实现全局异常处理 首先创建一个全局异常处理器类使用ControllerAdvice注解标记并在该类中定义异常处理方法。 package com.example.demo.exception; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; ControllerAdvice RestController public class GlobalExceptionHandler {     ExceptionHandler(Exception.class)     ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)     public ResponseEntityString handleGlobalException(Exception e) {         return new ResponseEntity(An error occurred: e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);     }     ExceptionHandler(NotFoundException.class)     ResponseStatus(HttpStatus.NOT_FOUND)     public ResponseEntityString handleNotFoundException(NotFoundException e) {         return new ResponseEntity(Resource not found: e.getMessage(), HttpStatus.NOT_FOUND);     } } 在上面的例子中我们创建了一个GlobalExceptionHandler类并使用ControllerAdvice注解标记它。在这个类中我们定义了两个异常处理方法分别处理Exception和NotFoundException。这些方法使用ExceptionHandler注解来指定要处理的异常类型并根据异常类型返回自定义的错误信息和HTTP状态码。 接下来我们创建一个自定义的NotFoundException异常类 package com.example.demo.exception; public class NotFoundException extends RuntimeException {     public NotFoundException(String message) {         super(message);     } } 最后让我们来看一个使用全局异常处理的Controller示例 package com.example.demo.controllers; import com.example.demo.exception.NotFoundException; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; RestController public class HelloController {     GetMapping(/hello/{name})     public String hello(PathVariable String name) {         if (name.equals(admin)) {             return Hello, admin!;         } else {             throw new NotFoundException(User not found);         }     } } 在上面的示例中我们创建了一个简单的RestController并定义了一个hello方法。当传入的name参数为admin时返回Hello, admin!否则抛出NotFoundException异常。 通过以上步骤我们已经成功实现了全局异常处理。当应用程序中的hello方法抛出NotFoundException异常时全局异常处理器会捕获并处理该异常并返回自定义的错误信息和HTTP状态码。这种方法可以让您集中处理应用程序中的异常并统一返回友好的错误信息给客户端。 9.Spring Boot中的切面AOP处理 Spring Boot的AOP面向切面编程可以在许多实际应用场景中发挥作用以下是一些常见的实际应用场景 1.日志记录最常用的使用 AOP可以用于记录方法的执行时间、参数、返回值等信息从而实现统一的日志记录提高代码的可维护性和可观察性。 2. 事务管理 AOP可以用于管理事务的开启、提交、回滚等操作从而实现统一的事务管理确保数据操作的一致性和完整性。Transactional注解本身并不是AOP但它通常与AOP结合使用因为它会触发Spring框架的事务管理机制而这一机制通常是通过AOP来实现的。通过使用Transactional注解您可以将事务管理的责任交给Spring框架从而让框架来处理事务的开启、提交和回滚而无需手动管理事务。 3. 权限控制 AOP可以用于实现权限控制例如检查用户是否有权限执行某个方法从而实现统一的权限管理。 首先您需要创建一个切面类该类包含权限检查的逻辑。假设我们要实现一个简单的权限控制只有具有admin角色的用户才能执行某些操作 import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; Aspect Component public class PermissionAspect {     Before(execution(* com.example.service.*.*(..)) annotation(com.example.annotation.AdminOnly))     public void checkPermission(JoinPoint joinPoint) {         // 在执行方法前进行权限检查         if (!currentUserHasAdminRole()) {             throw new SecurityException(Permission denied);         }     }     private boolean currentUserHasAdminRole() {         // 检查当前用户是否具有admin角色         // 实际逻辑根据您的需求来实现         return true; // 假设当前用户具有admin角色     } } 在上述示例中我们创建了一个名为PermissionAspect的切面类其中定义了一个名为checkPermission的方法。该方法使用Before注解来指定在目标方法执行前进行权限检查。在checkPermission方法中我们检查当前用户是否具有admin角色如果没有则抛出SecurityException异常。 接下来我们需要创建一个自定义注解AdminOnly该注解用于标记需要进行权限控制的方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface AdminOnly {     // 空注解仅用于标记需要进行权限控制的方法 } 现在我们可以在需要进行权限控制的方法上使用AdminOnly注解来标记 Service public class MyService {     AdminOnly     public void performAdminOperation() {         // 只有具有admin角色的用户才能执行该方法     } } 在上述示例中我们使用AdminOnly注解标记了performAdminOperation方法表示只有具有admin角色的用户才能执行该方法。 通过以上步骤我们就实现了一个简单的基于AOP的权限控制。在实际应用中您可以根据具体需求扩展权限控制的逻辑例如从数据库或外部系统中获取用户权限信息等。 4. 性能监控 AOP可以用于监控方法的性能例如记录方法的执行时间、资源消耗等信息从而实现统一的性能监控。 import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; Aspect Component public class PerformanceMonitorAspect {     Around(execution(* com.example.service.*.*(..)))     public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {         long startTime System.currentTimeMillis();         Object result joinPoint.proceed(); // 调用目标方法         long endTime System.currentTimeMillis();         long executionTime endTime - startTime;         System.out.println(joinPoint.getSignature() executed in executionTime ms);         return result;     } } 5. 异常处理 AOP可以用于捕获方法抛出的异常并进行统一的异常处理例如记录异常信息、发送警告通知等。 AOP异常处理和统一捕捉异常处理通常不会直接冲突而是可以互补使用。这两种方式可以在不同层次上进行异常处理以便达到更全面的异常处理和管理。 在实际应用中您可以这样组织异常处理逻辑 1. AOP异常处理使用AOP来捕获特定方法执行过程中抛出的异常可以针对特定的业务逻辑或服务进行异常处理。这种方式可以让您在方法级别上进行异常处理例如记录日志、执行特定的补救操作等。 2. 统一捕捉异常处理在应用的顶层或全局异常处理器中统一捕获和处理未被特定业务逻辑处理的异常。这种方式可以让您在应用级别上进行异常处理例如向用户返回统一的错误信息、记录全局异常日志等。 6. 缓存管理 AOP可以用于实现方法级别的缓存管理例如缓存方法的返回值从而提高系统的性能和响应速度。 7. 日志脱敏 AOP可以用于实现统一的日志脱敏例如对敏感信息进行处理后再记录日志确保日志中不包含敏感信息。 8. 性能优化 AOP可以用于实现性能优化例如对方法进行切面优化、缓存优化等从而提高系统的性能和效率。 9. 跟踪和监控 AOP可以用于实现方法执行的跟踪和监控例如记录方法的执行路径、参数值等信息从而实现系统的跟踪和监控。 10. 统一异常处理 AOP可以用于统一处理应用程序中的异常例如记录异常信息、返回统一的错误页面或错误信息等。 10.Spring Boot集成MyBatis 在Spring Boot中集成MyBatis非常简单主要涉及以下几个步骤 1. 添加MyBatis和相关依赖在pom.xml文件中添加MyBatis和MyBatis-Spring Boot Starter的依赖。 2. 配置数据源在application.properties或application.yml中配置数据库连接信息。 3. 创建MyBatis映射器Mapper接口和对应的XML文件在src/main/java目录下创建MyBatis映射器接口。 4. 配置MyBatis在Spring Boot的配置类中添加MapperScan注解指定Mapper接口的包路径。 通过以上步骤就可以在Spring Boot中集成MyBatis并且使用MyBatis进行数据库操作。在实际应用中可以根据具体需求对MyBatis的配置进行扩展例如添加分页插件、多数据源配置等。 11.Spring Boot事务配置管理 常见问题 异常并没有被 ”捕获“ 到 因为 Spring Boot 默认的事务规则是遇到运行异常RuntimeException和程序错误Error才会回滚。比如上面我们的例子中抛出的 RuntimeException 就没有问题但是抛出 SQLException 就无法回滚了。针对非运行时异常如果要进行事务回滚的话可以在 Transactional 注解中使用 rollbackFor 属性来指定异常比如 Transactional(rollbackFor Exception.class)这样就没有问题了所以在实际项目中一定要指定异常。 异常被 ”吃“ 掉 try…catch 事务的范围原文链接https://blog.csdn.net/cuiqwei/article/details/118188540 12.Spring Boot中使用监听器 在Java Web开发中Web监听器是非常常用的组件它们可以用于各种用途比如 1. 应用程序初始化和销毁通过ServletContextListener监听器可以在Web应用程序初始化和销毁时执行特定的逻辑比如加载配置、初始化资源或者释放资源等。 2. 会话管理通过HttpSessionListener监听器可以监听会话的创建和销毁事件从而实现对用户会话的管理和监控。 3. 请求处理通过ServletRequestListener监听器可以监听HTTP请求的创建和销毁事件以及请求属性的变化从而实现对请求的监控和控制。 在Spring框架中Web监听器也是可以使用的Spring提供了一些方便的方式来集成和使用Servlet规范中的监听器比如通过WebListener注解或注册监听器的方式。这些监听器可以用于与Spring应用程序的其他组件集成从而实现更灵活和强大的Web应用程序开发。 因此Web监听器是Web开发中非常有用的工具可以帮助开发者实现对Web应用中各种事件的监听和处理从而实现更灵活和可控的Web应用程序开发。 13.Spring Boot中使用拦截器Interceptor 在Spring Boot应用程序中拦截器Interceptor通常比监听器Listener更常用。虽然监听器和拦截器都可以用于处理特定事件或请求但它们的使用场景和功能有所不同。 拦截器Interceptor的常见使用场景 1. 请求处理拦截器通常用于拦截HTTP请求在请求处理前、后或完成时执行特定的逻辑比如日志记录、权限验证、请求参数预处理等。 2. 全局处理拦截器可以全局地对所有请求进行处理比如添加通用的响应头、异常处理等。 3. 权限控制拦截器可以用于实现对请求的权限控制和认证比如验证用户登录状态、检查用户权限等。 14.Spring Boot中集成Redis Redis是一种开源的内存数据库常用于缓存、会话管理、消息队列等。以下是集成Redis到Spring Boot应用程序的基本步骤 1. 添加依赖 2. 配置Redis连接信息 3.创建Redis配置类 4. 使用Redis 15.Spring Boot中集成 Shiro ShiroApache Shiro是一个强大且易于使用的Java安全框架用于身份验证、授权、加密和会话管理等安全操作。Shiro的主要功能包括 1. 身份验证Authentication验证用户的身份确保用户是谁。Shiro支持多种身份验证方法如基于用户名和密码的验证、基于LDAP的验证、基于OAuth的验证等。 2. 授权Authorization确定用户是否有权限执行某个操作。Shiro提供了细粒度的授权控制可以基于角色、权限、资源等进行授权管理。 3. 加密Cryptography提供了常见的加密算法和工具用于对密码等敏感信息进行加密存储和验证。 4. 会话管理Session Management管理用户会话包括创建、销毁、更新会话等操作。Shiro支持基于Cookie和URL重写的会话管理方式。 5. Web集成Web Integration提供了与Web应用程序集成的支持包括Filter、Servlet、Listener等可轻松与基于Servlet的框架如Spring MVC集成。 6. 缓存支持CachingShiro提供了缓存支持可以缓存用户信息、权限信息等提高系统性能。 7. 插件化PluggabilityShiro的设计是高度模块化的可以通过插件的方式扩展和定制功能。 总的来说Shiro可以帮助开发人员快速、灵活地实现应用程序的安全功能保护系统免受各种安全威胁。它的易用性和功能丰富性使得它成为Java领域中最受欢迎的安全框架之一。 三个核心组件 它们共同工作以提供身份验证、授权和会话管理功能。这三个核心组件是 1. Subject主体 - Subject代表当前用户可以是一个人、设备或者第三方服务。Subject可以是任何与应用程序交互的实体用于执行身份验证和授权操作。 - Subject是Shiro中的核心接口封装了用户的安全操作如登录、登出、检查权限等。开发人员通过Subject与Shiro进行交互。 Subject认证主体。它包含两个信息Principals 和 Credentials。 Principals身份。可以是用户名邮件手机号码等等用来标识一个登录主体身份 Credentials凭证。常见有密码数字证书等等。 用户在登录的时候Shiro 需要去进行身份认证就需要 Subject 认证主体。 2. SecurityManager安全管理器 - SecurityManager是Shiro的核心组件负责管理所有的安全操作。 - 安全管理器负责协调Subject、Realm、SessionManager和其他安全组件之间的交互。 - SecurityManager是整个Shiro框架的入口点所有的安全操作都通过SecurityManager来执行。 安全管理员。这是 Shiro 架构的核心它就像 Shiro 内部所有原件的保护伞一样。我们在项目中一般都会配置 SecurityManager开发人员大部分精力主要是在 Subject 认证主体上面。我们在与 Subject 进行交互的时候实际上是 SecurityManager 在背后做一些安全操作。 3. Realm领域 - Realm是Shiro与应用程序进行交互的桥梁用于验证用户的身份和授予用户权限。 - Realm通常包含了用户信息、角色信息和权限信息用于进行身份验证和授权操作。 - 应用程序可以配置一个或多个RealmShiro将根据配置的顺序依次尝试验证用户身份和授权。 这三个核心组件共同协作构成了Shiro框架的基础架构。Subject代表用户SecurityManager管理安全操作而Realm用于验证用户身份和授权。通过这些组件的协作Shiro提供了一个灵活、可定制的安全解决方案帮助开发人员保护应用程序免受各种安全威胁。 Shiro 身份认证流程 Apache Shiro的身份认证流程通常包括以下步骤 1. **创建SecurityManager对象**首先需要创建一个SecurityManager对象作为Shiro安全框架的入口点。SecurityManager负责管理所有的安全操作。 2. **Subject登录**用户尝试登录时需要获取当前的Subject对象。可以通过SecurityUtils.getSubject()方法获取Subject对象然后调用Subject.login(AuthenticationToken token)方法进行登录。 3. **构建AuthenticationToken对象**在登录时用户需要提供身份信息如用户名和凭证信息如密码。这些信息通常被封装在一个AuthenticationToken对象中以便Shiro进行验证。 4. **AuthenticationToken验证**AuthenticationToken对象将被传递给配置的Realm进行验证。Realm会根据提供的身份信息和凭证信息验证用户的身份如果验证成功则返回一个表示用户身份的AuthenticationInfo对象。 5. **认证结果处理**一旦Realm验证成功Shiro将会更新Subject的状态标记用户为已认证状态。开发人员可以根据需要处理认证成功的逻辑。 6. **处理认证失败**如果身份验证失败Shiro将抛出相应的异常或错误信息。开发人员可以根据具体情况处理认证失败的逻辑。 7. **完成认证**一旦用户成功通过身份验证用户将被标记为已认证状态可以继续执行受保护的操作。 总的来说Shiro的身份认证流程涉及创建SecurityManager对象、获取Subject对象、构建和验证AuthenticationToken对象、处理认证结果等步骤。通过这个流程Shiro可以有效地进行用户身份验证确保系统的安全性。 Shiro 权限认证 权限permission即操作资源的权利比如访问某个页面以及对某个模块的数据的添加修改删除查看的权利 角色role指的是用户担任的的角色一个角色可以有多个权限 用户user在 Shiro 中代表访问系统的用户即上面提到的 Subject 认证主体。 Spring Boot 集成 Shiro 过程  1. 添加Shiro和相关依赖 在pom.xml文件中添加Shiro和相关依赖 dependency     groupIdorg.apache.shiro/groupId     artifactIdshiro-spring/artifactId     version1.8.0/version /dependency 1.1数据库表数据初始化  三张表用户表、角色表和权限表 2.创建自定义Realm 创建一个继承自AuthorizingRealm的自定义Realm类用于实现用户的认证和授权逻辑。在Realm中你可以根据实际需求重写doGetAuthenticationInfo()方法和doGetAuthorizationInfo()方法。 doGetAuthenticationInfo()方法和doGetAuthorizationInfo()方法是Apache Shiro中Realm类的两个重要方法用于实现用户身份认证和授权逻辑。 - **doGetAuthenticationInfo(AuthenticationToken token)方法**在用户登录时Shiro会调用这个方法来验证用户的身份信息。开发人员需要在这个方法中实现用户身份信息的验证逻辑例如检查用户名和密码是否匹配。如果验证成功需要返回一个AuthenticationInfo对象如果验证失败可以返回null或抛出相应异常。 - **doGetAuthorizationInfo(PrincipalCollection principals)方法**在用户进行访问控制时Shiro会调用这个方法来获取用户的授权信息。开发人员需要在这个方法中实现用户的授权逻辑例如获取用户的角色和权限信息。根据用户的角色和权限需要构建并返回一个AuthorizationInfo对象Shiro会根据这个信息来决定用户是否有权限执行特定操作。 public class MyRealm extends AuthorizingRealm {     // 用户身份认证     Override     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {         UsernamePasswordToken usernamePasswordToken (UsernamePasswordToken) token;         String username usernamePasswordToken.getUsername();         String password String.valueOf(usernamePasswordToken.getPassword());         // 根据用户名查询用户信息这里假设用户信息存储在数据库中         User user userService.getUserByUsername(username);         if (user null || !password.equals(user.getPassword())) {             throw new IncorrectCredentialsException(用户名或密码错误);         }         return new SimpleAuthenticationInfo(user, user.getPassword(), getName());     }     // 用户授权     Override     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {         User user (User) principals.getPrimaryPrincipal();         SimpleAuthorizationInfo authorizationInfo new SimpleAuthorizationInfo();         // 获取用户角色信息         SetString roles userService.getRolesByUsername(user.getUsername());         authorizationInfo.setRoles(roles);         // 获取用户权限信息         SetString permissions userService.getPermissionsByUsername(user.getUsername());         authorizationInfo.setStringPermissions(permissions);         return authorizationInfo;     } } 从上面两个方法中可以看出验证身份的时候是根据用户输入的用户名先从数据库中查出该用户名对应的用户这时候并没有涉及到密码也就是说到这一步的时候即使用户输入的密码不对也是可以查出来该用户的然后将该用户的正确信息封装到 authcInfo 中返回给 Shiro接下来就是Shiro的事了它会根据这里面的真实信息与用户前台输入的用户名和密码进行校验 这个时候也要校验密码了如果校验通过就让用户登录否则跳转到指定页面。同理权限验证的时候也是先根据用户名从数据库中获取与该用户名有关的角色和权限然后封装到 authorizationInfo 中返回给 Shiro                        原文链接https://blog.csdn.net/cuiqwei/article/details/118188540 3. 安全管理器SecurityManager配置 public class ShiroConfig {     Bean     public SecurityManager securityManager(MyRealm myRealm) {         DefaultWebSecurityManager securityManager new DefaultWebSecurityManager();         securityManager.setRealm(myRealm);         return securityManager;     }     Bean     public MyRealm myRealm() {         return new MyRealm();     } } 4. Shiro过滤器配置 Configuration public class ShiroConfig {       private static final Logger logger LoggerFactory.getLogger(ShiroConfig.class);          /**      * 注入Shiro过滤器      * param securityManager 安全管理器      * return ShiroFilterFactoryBean      */     Bean     public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {         // 定义shiroFactoryBean         ShiroFilterFactoryBean shiroFilterFactoryBeannew ShiroFilterFactoryBean();           // 设置自定义的securityManager         shiroFilterFactoryBean.setSecurityManager(securityManager);           // 设置默认登录的url身份认证失败会访问该url         shiroFilterFactoryBean.setLoginUrl(/login);         // 设置成功之后要跳转的链接         shiroFilterFactoryBean.setSuccessUrl(/success);         // 设置未授权界面权限认证失败会访问该url         shiroFilterFactoryBean.setUnauthorizedUrl(/unauthorized);           // LinkedHashMap是有序的进行顺序拦截器配置         MapString,String filterChainMap new LinkedHashMap();           // 配置可以匿名访问的地址可以根据实际情况自己添加放行一些静态资源等anon表示放行         filterChainMap.put(/css/**, anon);         filterChainMap.put(/imgs/**, anon);         filterChainMap.put(/js/**, anon);         filterChainMap.put(/swagger-*/**, anon);         filterChainMap.put(/swagger-ui.html/**, anon);         // 登录url 放行         filterChainMap.put(/login, anon);           // “/user/admin” 开头的需要身份认证authc表示要身份认证         filterChainMap.put(/user/admin*, authc);         // “/user/student” 开头的需要角色认证是“admin”才允许         filterChainMap.put(/user/student*/**, roles[admin]);         // “/user/teacher” 开头的需要权限认证是“user:create”才允许         filterChainMap.put(/user/teacher*/**, perms[\user:create\]);           // 配置logout过滤器         filterChainMap.put(/logout, logout);           // 设置shiroFilterFactoryBean的FilterChainDefinitionMap         shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);         logger.info(shiroFilterFactoryBean注册完成);         return shiroFilterFactoryBean;     } } 5.过滤器Filters Apache Shiro中的过滤器Filters是用于拦截和处理用户请求的组件可以实现对请求的安全验证和访问控制。以下是几个常用的 Shiro 过滤器及其权限 1. **anon**AnonymousFilter - anon 是 Shiro 中的匿名访问过滤器用于表示允许匿名用户访问的资源。 - 这个过滤器通常用于配置不需要认证即可访问的 URL 路径如登录页面、注册页面等。 - 该过滤器的权限是允许未认证的用户访问特定资源。 2. **authc**FormAuthenticationFilter - authc 是 Shiro 中的基本认证过滤器用于表示需要进行身份认证后才能访问的资源。 - 当用户访问需要认证的资源时该过滤器会强制用户进行身份认证通常通过用户名密码登录。 - 该过滤器的权限是要求用户已通过身份认证才能访问特定资源。 3. **logout**LogoutFilter - logout 是 Shiro 中的登出过滤器用于处理用户的登出操作。 - 当用户访问登出 URL 时该过滤器会执行用户的登出操作清除用户的认证信息。 - 该过滤器的权限是处理用户登出操作不需要特定的权限。 4. **perms**PermissionsAuthorizationFilter - perms 是 Shiro 中的权限验证过滤器用于根据用户的权限控制访问权限。 - 可以配置该过滤器来要求用户具有特定的权限才能访问资源如 perms[user:create] 表示需要 user:create 权限。 - 该过滤器的权限是根据用户的权限进行访问控制。 5. **roles**RolesAuthorizationFilter - roles 是 Shiro 中的角色验证过滤器用于根据用户的角色控制访问权限。 - 可以配置该过滤器来要求用户具有特定的角色才能访问资源如 roles[admin] 表示需要 admin 角色。 - 该过滤器的权限是根据用户的角色进行访问控制。 这些是 Apache Shiro 中几个常用的过滤器及其权限通过合理配置这些过滤器可以实现对用户请求的安全验证和访问控制确保系统资源的安全访问。 6.登陆 Controller RequestMapping(/user) public class UserController {       /**      * 用户登录接口      * param user user      * param request request      * return string      */     PostMapping(/login)     public String login(User user, HttpServletRequest request) {           // 根据用户名和密码创建token         UsernamePasswordToken token new UsernamePasswordToken(user.getUsername(), user.getPassword());         // 获取subject认证主体         Subject subject SecurityUtils.getSubject();         try{             // 开始认证这一步会跳到我们自定义的realm中             subject.login(token);             request.getSession().setAttribute(user, user);             return success;         }catch(Exception e){             e.printStackTrace();             request.getSession().setAttribute(user, user);             request.setAttribute(error, 用户名或密码错误);             return login;         }     } } 16.Spring Boot 中整合 Lucene 可以让你在应用程序中实现强大的全文搜索功能。以下是整合 Lucene 到 Spring Boot 项目中的基本步骤 ### 步骤 1. **添加依赖** 在 pom.xml 文件中添加 Lucene 依赖 dependency        groupIdorg.apache.lucene/groupId        artifactIdlucene-core/artifactId        version{version}/version    /dependency 2. **创建索引** - 创建一个 Lucene 索引用于存储文档信息。 - 索引可以包含文档的字段和内容。 3. **编写搜索服务** - 创建一个搜索服务类用于执行搜索操作。 - 在服务类中编写方法来执行搜索并返回结果。 4. **配置 Lucene** - 可以配置 Lucene 的 Analyzer、Directory 等组件用于索引和搜索操作。 5. **编写 Controller** - 创建一个 Spring Boot Controller处理搜索请求并调用搜索服务。 6. **执行搜索** - 在 Controller 中调用搜索服务执行搜索操作。 - 将搜索结果返回给前端页面或客户端。 ### 示例代码 下面是一个简单的示例代码演示如何在 Spring Boot 中使用 Lucene 实现搜索功能 // 创建 Lucene 索引 public void createIndex() {     // 创建索引目录     Directory indexDir FSDirectory.open(Paths.get(/path/to/index));          // 创建分词器     Analyzer analyzer new StandardAnalyzer();          // 创建索引写入器     IndexWriterConfig config new IndexWriterConfig(analyzer);     IndexWriter writer new IndexWriter(indexDir, config);          // 创建文档     Document doc new Document();     doc.add(new TextField(content, Hello, Lucene!, Field.Store.YES));          // 将文档添加到索引     writer.addDocument(doc);          // 提交更改并关闭写入器     writer.commit();     writer.close(); } // 执行搜索 public ListString search(String queryStr) {     ListString results new ArrayList();          // 创建索引目录     Directory indexDir FSDirectory.open(Paths.get(/path/to/index));          // 创建索引读取器     IndexReader reader DirectoryReader.open(indexDir);     IndexSearcher searcher new IndexSearcher(reader);          // 创建查询解析器     QueryParser parser new QueryParser(content, new StandardAnalyzer());     Query query parser.parse(queryStr);          // 执行搜索     TopDocs topDocs searcher.search(query, 10);          // 处理搜索结果     for (ScoreDoc scoreDoc : topDocs.scoreDocs) {         Document doc searcher.doc(scoreDoc.doc);         results.add(doc.get(content));     }          return results; }
http://www.hkea.cn/news/14278294/

相关文章:

  • 快手流量推广网站成都软件外包开发
  • 创建qq网站吗dw建网站
  • 空间站 对接如何做能切换语言的网站
  • 谷歌广告投放教程推广优化公司网站
  • 怎么套模板 网站nike定制在哪个app
  • 定制网站与模板网站苏州电商系统开发
  • 汕头搭建建站安阳论坛最新消息
  • 在线游戏网站南宁工程造价建设信息网站
  • 网站设计网站建设毕业文稿宁波网络推广推荐
  • 义乌外贸建网站桂林阳朔
  • 织梦网站地图调用全站文章响应式网站推广
  • 工作细胞中文版免费完整版第一季百度seo关键词优化公司
  • 网站建设与实践吧网站做软件的软件下载
  • 网站规划建设与管理维护教学大纲贵州软件开发 网站开发
  • 惠州网站制作培训标书制作教程全过程
  • app应用网站单页模板推广联盟网站怎么做
  • 北京网站建设公司 网络服务知名网站建设设计
  • 龙华网站建设yihe kj大公司网站建设建网站
  • 石家庄企业自助建站湖南衡阳市建设工程造价网站
  • 网站模板文件在哪里下载成都seo达人
  • 网站建设的网青岛网上房地产网签查询
  • 郑州网站seo公司在哪个网站上做实验仪器比较好
  • 2019流行做什么网站网站外贸建站是什么意思
  • 宝安网站制作哪家强德州做网站哪家好
  • 改版百度不收录网站网络设计方案ppt
  • 机械建设网站制作上海如何优化网站
  • 做网站用的品牌营销增长新参考价格
  • 青海专业网页设计免费建站提供设计网站效果图
  • 紫搜科技建站教育网站制作费用
  • 海港区网站快排seo原创小说手机网站制作需要多少钱