• 【SpringCloud】微服务初始化


    在实际开发中,我们会对独立的模块进行封装,使用微服务来承载这个模块的所有功能。

    那么,如何从零搭建一个微服务呢?

    本文建立的微服务包含以下几点基础能力:

    1)支持SSM框架

    2)Redis缓存

    3)Oss文件服务

    4)全局Controller异常处理

    5)全局Controller日志打印(采用AOP技术)

    6)拦截器

    7)全局跨域处理

    8)Mybatis(DAO)自动化生成配置

    9)通用工具类

    以下为具体代码或者配置:

    一、支持SSM框架

    通过pom.xml配置来解决(假设服务命为message-service)

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.cheng2839.message</groupId>
        <artifactId>message-service</artifactId>
        <name>message-service</name>
        <version>1.0.0.0</version>
        <packaging>jar</packaging>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.6.RELEASE</version>
        </parent>
    <!-- 本文地址:https://www.cnblogs.com/cheng2839/p/14788655.html --> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <mainClass>com.cheng2839.message.MessageApplication</mainClass> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-client</artifactId> </dependency> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.5.0</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.0</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.7</version> </dependency> <!-- 添加oracle jdbc driver --> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc14</artifactId> <version>10.2.0.4.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.20</version> </dependency> </dependencies> <profiles> <profile> <id>release</id> <properties> <project.release.version>1.0</project.release.version> </properties> </profile> </profiles> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <distributionManagement> </distributionManagement> <repositories> </repositories> <pluginRepositories> </pluginRepositories> <build> <!-- 添加资源 --> <resources> <resource> <directory>src/main/java</directory> <includes> <!--包含文件夹以及子文件夹下所有资源--> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <!-- src/main/resources下的指定资源放行 --> <includes> <include>**/*.properties</include> <include>**/*.yml</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-archetype-plugin</artifactId> <version>2.2</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.2</version> <executions> <execution> <id>attach-sources</id> <phase>verify</phase> <goals> <goal>jar-no-fork</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <finalName>message-service</finalName> <!--<outputDirectory>../target</outputDirectory>--> <!--<fork>true</fork>--> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.18.1</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.2</version> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.17</version> </dependency> </dependencies> <configuration> <!--配置文件的路径--> <configurationFile>src/main/resources/generatorConfig.xml</configurationFile> <overwrite>true</overwrite> </configuration> </plugin> </plugins> </build> <modules> </modules> </project>

    二、Redis缓存

    首先,创建redis配置类

    package com.cheng2839.message.config;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cache.CacheManager;
    import org.springframework.cache.annotation.CachingConfigurerSupport;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.cache.RedisCacheManager;
    import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
    * 本文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
    */
    @Configuration
    public class RedisConfig extends CachingConfigurerSupport { Logger logger = LoggerFactory.getLogger(RedisConfig.class); @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.password}") private String password; @Value("${spring.redis.database}") private int database; @Value("${spring.redis.timeout}") private String timeout; @Bean JedisConnectionFactory jedisConnectionFactory() { JedisConnectionFactory factory = new JedisConnectionFactory(); factory.setHostName(this.host); factory.setPort(this.port); factory.setPassword(this.password); factory.setDatabase(this.database); logger.info("jedisConnectionFactory:host{},port{},database{}",host,port,this.database); return factory; } @Bean public RedisTemplate redisTemplate() { RedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(jedisConnectionFactory()); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new StringRedisSerializer()); template.setDefaultSerializer(new StringRedisSerializer()); template.afterPropertiesSet(); logger.info("redisTrafficTemplate"); return template; } @Bean public CacheManager cacheManager(RedisTemplate redisTemplate) { RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); //默认超时时间,单位秒 cacheManager.setDefaultExpiration(Integer.parseInt(timeout)); //根据缓存名称设置超时时间,0为不超时 Map<String,Long> expires = new ConcurrentHashMap<>(); cacheManager.setExpires(expires); return cacheManager; } }

    其次,创建service业务类

    package com.cheng2839.message.service.impl;
    
    import com.alibaba.fastjson.JSON;
    import com.cheng2839.message.service.RedisService;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.data.redis.core.ClusterOperations;
    import org.springframework.data.redis.core.GeoOperations;
    import org.springframework.data.redis.core.HashOperations;
    import org.springframework.data.redis.core.HyperLogLogOperations;
    import org.springframework.data.redis.core.ListOperations;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.SetOperations;
    import org.springframework.data.redis.core.ValueOperations;
    import org.springframework.data.redis.core.ZSetOperations;
    import org.springframework.stereotype.Service;
    import org.springframework.util.StringUtils;
    
    import java.util.Collection;
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 本文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
     */
    @Service
    public class RedisServiceImpl implements RedisService {
        private static Logger logger = LoggerFactory.getLogger(RedisServiceImpl.class);
        @Autowired
        @Qualifier("redisTemplate")
        private RedisTemplate redisTemplate;
    
        /**
         * 保存字符串数据
         * 本文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
         */
        public void setForString(String key, Object value) {
            String valueStr = null;
            if (value == null) {
                valueStr = null;
            } else if (value instanceof String) {
                valueStr = value.toString();
            } else {
                valueStr = JSON.toJSONString(value);
            }
            logger.info("缓存数据key:{},value:{}", key, valueStr);
            redisTemplate.opsForValue().set(key, valueStr);
        }
    
        /**
         * 保存字符串数据,并设置数据有效时间,单位秒
         */
        public void setForString(String key, Object value, long timeout) {
            setForString(key, value, timeout, TimeUnit.SECONDS);
        }
    
        /**
         * 保存字符串数据,并设置数据有效时间,时间和时间单位自定义
         * 本文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
         */
        public void setForString(String key, Object value, long timeout, TimeUnit unit) {
            String valueStr = null;
            if (value == null) {
                valueStr = null;
            } else if (value instanceof String) {
                valueStr = value.toString();
            } else {
                valueStr = JSON.toJSONString(value);
            }
            logger.info("缓存数据timeout:{},unit:{},key:{},value:{}", timeout, unit, key, valueStr);
            redisTemplate.opsForValue().set(key, valueStr, timeout, unit);
        }
    
        /**
         * 添加map集合字符串数据
         * 本文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
         */
        public void multiSetForString(Map<String, Object> map) {
            logger.info("multiSetForString map:{}", JSON.toJSONString(map));
            redisTemplate.opsForValue().multiSet(map);
        }
    
        /**
         * 获取key对应的字符串数据
         * 本文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
         */
        public String getForString(String key) {
            return (String) redisTemplate.opsForValue().get(key);
        }
    
        /**
         * 获取key对应的数据,并将value(json格式) 转换为对象
         */
        public <T> T getObjectForString(String key, Class<T> clazz) {
            String value = (String) redisTemplate.opsForValue().get(key);
            logger.info("方法getObjectForString, key:{},value:{}", key, value);
            if (StringUtils.isEmpty(value)) {
                return null;
            }
    
            return JSON.parseObject(value, clazz);
        }
    
        /**
         * 获取key对应的数据,并将value(json格式) 转换为List对象
         */
        public <T> List<T> getListForString(String key, Class<T> clazz) {
            String value = (String) redisTemplate.opsForValue().get(key);
            logger.info("getListForString, key:{},value:{}", key, value);
            if (StringUtils.isEmpty(value)) {
                return Collections.emptyList();
            }
            return JSON.parseArray(value, clazz);
        }
    
    
        /**
         * 查询一组key的数据
         */
        public List<String> multiGetForString(Collection<String> keys) {
            logger.info("multiGetForString, key:{}", keys);
            return redisTemplate.opsForValue().multiGet(keys);
        }
    
    
        /**
         * 查询字符串key值的长度
         */
        public Long sizeForString(String key) {
            logger.info("sizeForString, key:{}", key);
            return redisTemplate.opsForValue().size(key);
        }
    
    
        /**
         * 删除指定key
         */
        public void delete(Object key) {
            logger.info("delete, key:{}", key);
            redisTemplate.delete(key);
        }
    
        /**
         * 删除指定key集合
         */
        public void delete(Collection<Object> keys) {
            logger.info("delete, keys:{}", JSON.toJSONString(keys));
            redisTemplate.delete(keys);
        }
    
        /**
         * 查询key存在
         */
        public Boolean hasKey(Object key) {
            logger.info("hasKey, key:{}", key);
            return redisTemplate.hasKey(key);
        }
    
        /**
         * 设置keky的过期时间,可以自定义时长  和时间单位
         * 本文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
         */
        public Boolean expire(Object key, final long timeout, final TimeUnit unit) {
            logger.info("expire, key:{},timeout:{},unit:{}", key, timeout, unit);
            return redisTemplate.expire(key, timeout, unit);
        }
    
    
        /**
         * redis基础接口
         * 本文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
         */
        public ValueOperations opsForValue() {
            return redisTemplate.opsForValue();
        }
    
        /**
         * redis基础接口
         */
        public HashOperations opsForHash() {
            return redisTemplate.opsForHash();
        }
    
        /**
         * redis基础接口
         */
        public ListOperations opsForList() {
            return redisTemplate.opsForList();
        }
    
        /**
         * redis基础接口
         * 本文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
         */
        public ZSetOperations opsForZSet() {
            return redisTemplate.opsForZSet();
        }
    
        /**
         * redis基础接口
         */
        public SetOperations opsForSet() {
            return redisTemplate.opsForSet();
        }
    
        /**
         * redis基础接口
         */
        public ClusterOperations opsForCluster() {
            return redisTemplate.opsForCluster();
        }
    
        /**
         * redis基础接口
         * 本文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
         */
        public GeoOperations opsForGeo() {
            return redisTemplate.opsForGeo();
        }
    
        /**
         * redis基础接口
         * 本文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
         */
        public HyperLogLogOperations opsForHyperLogLog() {
            return redisTemplate.opsForHyperLogLog();
        }
    
    }

    最后,配置message-service-test.properties或者application.xml文件

    spring.redis.database=2
    spring.redis.host=192.168.8.123
    spring.redis.password=test123456
    spring.redis.port=6379
    spring.redis.pool.max-active=8
    spring.redis.expire=10
    spring.redis.max-wait=200
    spring.redis.timeout=10000

    三、Oss文件服务

    四、全局Controller异常处理

    在controller包下创建类

    package com.cheng2839.message.controller.common;
    
    import com.cheng2839.message.common.model.RsJsonResult;
    import com.cheng2839.message.common.enums.BasicErrorEnum;
    import com.cheng2839.message.common.exception.BasicException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    /**
     * 原文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
     *
     */
    @ControllerAdvice
    @ResponseBody
    public class MessageExceptionHandler {
        private Logger logger = LoggerFactory.getLogger(MessageExceptionHandler.class);
    
        @ExceptionHandler(value = MethodArgumentNotValidException.class)
        public RsJsonResult<String> methodExceptionHandler(MethodArgumentNotValidException exception) {
            String errMsg = exception.getBindingResult().getAllErrors().get(0).getDefaultMessage();
            logger.error("Interface[message] MethodArgumentNotValidException : {}",errMsg);
            return RsJsonResult.error(BasicErrorEnum.BASIC_PARAM_ERROR.getCode(), errMsg);
        }
    
        @ExceptionHandler(value = BasicException.class)
        public RsJsonResult<String> methodExceptionHandler(BasicException exception) {
            String errMsg = exception.getMessage();
            logger.error("Interface[message] BasicException : {}",errMsg);
            return RsJsonResult.error(BasicErrorEnum.BASIC_ERROR.getCode(), errMsg);
        }
    
        @ExceptionHandler(value = Exception.class)
        public RsJsonResult<String> methodExceptionHandler(Exception exception) {
            String errMsg = exception.getMessage();
            logger.error("Interface[message] Exception : {}", exception);
            return RsJsonResult.error(BasicErrorEnum.BASIC_ERROR.getCode(), errMsg);
        }
    
    }

    五、全局Controller日志打印(采用AOP技术)

     可参考我以前的博文AOP日志拦截器 https://www.cnblogs.com/cheng2839/p/12614108.html

    六、拦截器

     拦截器框架如下

    package com.cheng2839.message.interceptor;
    
    import com.alibaba.fastjson.JSON;
    import org.apache.commons.lang3.ArrayUtils;
    import org.apache.http.HttpStatus;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Arrays;
    import java.util.concurrent.TimeUnit;
    
    @Component
    public class MessageContextInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public final boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
            request.setAttribute(START_TIME, System.currentTimeMillis());
            //此处写具体的拦截逻辑
            } catch (Exception e) {
                logger.error("异常url:{}", request.getRequestURI());
                logger.error("初始化用户信息异常,异常:{}", e);
            }
            return false;
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
            logger.debug("清除信息:{}", MessageContext.getId());
            MessageContext.remove();
        }
    
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            super.postHandle(request, response, handler, modelAndView);
        }
    
    }

    七、全局CORS跨域处理

    通过全局配置类实现

    package com.cheng2839.message.config;
    
    import com.cheng2839.message.common.Constance;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpMethod;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.filter.CorsFilter;
    
    /**
    * 本文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
    */ @Configuration
    public class CorsConfig { private static CorsConfiguration buildConfig() { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedOrigin("*"); corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); corsConfiguration.setMaxAge(Constance.NUM_3600); corsConfiguration.addAllowedMethod(HttpMethod.POST); corsConfiguration.addAllowedMethod(HttpMethod.GET); corsConfiguration.addAllowedMethod(HttpMethod.DELETE); corsConfiguration.addAllowedMethod(HttpMethod.PUT); corsConfiguration.addAllowedMethod(HttpMethod.OPTIONS); corsConfiguration.setAllowCredentials(true); return corsConfiguration; } @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", buildConfig()); return new CorsFilter(source); } }

    八、Mybatis(DAO)自动化生成配置

    九、通用工具类

    1)自定义封装ListUtil工具类 https://www.cnblogs.com/cheng2839/p/13853903.html

    2)模拟postman开发的Http请求工具类 https://www.cnblogs.com/cheng2839/p/13226309.html

     3)加密解密工具类 https://www.cnblogs.com/cheng2839/p/12659932.html

    4)线程池管理工具类 https://www.cnblogs.com/cheng2839/p/12620079.html

    十、Mysql和Oracle双数据源无缝切换

    参考:https://www.cnblogs.com/cheng2839/p/14144516.html

    十一、参数校验

    可参考自定义注解校验工具类,大大提高开发效率

    或者使用内置的注解

    如下Controller

        @PostMapping(value = "/message/copy", produces = "application/json;charset=utf-8")
        public RsJsonResult<String> copy(@RequestBody @Validated(value = {MessageRequest.MessageCopy.class}) MessageRequest request) {
    }

    参数MessageRequest如下

    package com.cheng2839.message.controller.bean;
    
    import lombok.Data;
    import org.hibernate.validator.constraints.NotBlank;
    
    import javax.validation.constraints.NotNull;
    import javax.validation.constraints.Pattern;
    
    /**
     * @Description https://www.cnblogs.com/cheng2839
     * @Author cheng2839
     * @Date
     * @Version v1.0
     */
    @Data
    public class MessageRequest {
    
        @NotNull(message = "Id不能为空", groups = {MessageUpdate.class, MessageCopy.class})
        private Long id;
    
        private String status;
    
        @Pattern(message = "名称需1至15个字符", regexp = ".{1,15}", groups = {MessageInsert.class, MessageCopy.class})
        @NotBlank(message = "名称不能为空", groups = {MessageInsert.class, MessageCopy.class})
        private String name;
    
        private String desc;
    
        @NotNull(message = "urlId不能为空", groups = {MessageInsert.class})
        private Long urlId;
    
        public interface MessageInsert{}
    
        public interface MessageUpdate{}
    
        public interface MessageCopy{}
    
    }

    剩下就可以专心开发业务功能了

    备注:该博文技术点可供参考,此为作者原创,版权原因(如需要完整的微服务工程源码,仅需付费39元(现优惠价19元,截止2021年6月30日),备注微服务初始化邮箱,即可发至邮箱),如有需要可留言联系作者,请尊重作者时间和精力的耗费,见谅!

     

    ____________________________特此,勉励____________________________
    本文作者cheng2839
    本文链接https://www.cnblogs.com/cheng2839
    关于博主:评论和私信会在第一时间回复。
    版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
    声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
  • 相关阅读:
    PAT 甲级 1129 Recommendation System
    PAT 甲级 1129 Recommendation System
    PAT 甲级 1128 N Queens Puzzle (20 分)
    PAT 甲级 1128 N Queens Puzzle (20 分)
    PAT 甲级 1096 Consecutive Factors (20 分)
    PAT 甲级 1096 Consecutive Factors (20 分)
    PAT 甲级 1135 Is It A Red-Black Tree (30 分)
    PAT 甲级 1135 Is It A Red-Black Tree (30 分)
    AcWing 900. 整数划分
    AcWing 899. 编辑距离 线性dp
  • 原文地址:https://www.cnblogs.com/cheng2839/p/14788655.html
Copyright © 2020-2023  润新知