• Java开发工作中常见问题


    开发工具

    idea打开多微服务面板(workspace.xml)

    <component name="RunDashboard">
        <option name="configurationTypes">
          <set>
            <option value="SpringBootApplicationConfigurationType" />
          </set>
        </option>
        <option name="ruleStates">
          <list>
            <RuleState>
              <option name="name" value="ConfigurationTypeDashboardGroupingRule" />
            </RuleState>
            <RuleState>
              <option name="name" value="StatusDashboardGroupingRule" />
            </RuleState>
          </list>
        </option>
      </component>

    github提交一个项目

    1.github提交一个项目
    (1)github添加新仓库jucdemo2
    (2)添加客户端id_ras.pub秘钥(C:UsersCzz.sshid_ras.pub)
    (3)添加远程仓库:
    # 初始化本地仓库,并提交到本地仓库
    $ cd D:ideawkjucdemo
    $ git init
    $ git add .
    $ git commit -m 'first commit'
    # 关联远程仓库并推送项目
    $ git remote add origin git@github.com:line007/jucdemo2.git
    # 第一次推送
    $ git push -u origin master
    # 非第一次推送
    $  git push origin master
    
    2.git checkout远程分支、标签
    命令:git clone --branch [tags标签] [git地址] 或者 git clone --b [tags标签] [git地址]
    例如:git clone -b 1.4.1 https://github.com/jumpserver/coco.git
    
    git clone -b v6.3.0 https://github.com/theme-next/hexo-theme-next themes/next6.3

    idea-pom项目无法识别

    File->Settings->Build,Excecution,Deployment->Build Tools->Maven->Ignored Files
    
    查看是否存在maven pom被勾选,去掉勾选即可。

    linux

    1.常用命令
    -- 查看异常
    $ tail -n 400 /usr/local/xx/logs/app-demo/error.log
    
    -- 查看端口
    $ netstat -tunlp
    $ ps -aux | grep 668
    
    -- 查看前10个最大的文件
    $ du -a / | sort -nr | head -n 10
    
    $ nohup java -jar xxl-job-admin.jar & 
    $ nohup java -jar xxl-job-executor-sample.jar &
    
    2.nginx常用命令
    $ nginx -t
    $ ./nginx -s reload
    
    3.redis常用命令
    -- 查询删除KEY
    $ key *
    $ get menu_details::1_menu
    $ del menu_details::1_menu
    
    -- 清库
    // 删除当前数据库中的所有Key
    $ flushdb
    // 删除所有数据库中的key
    $ flushall

    Spring

    spring-auth2.0 自定义异常输出

    参考网址

    // 核心原理:定义WebResponseExceptionTranslator一个实现类,并将自定义异常处理类添加到认证服务器配置
    @Configuration 
    @EnableAuthorizationServer 
    public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
        @Autowired 
        private WebResponseExceptionTranslator webResponseExceptionTranslator;
        /** 用来配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services) */ 
        @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 
            ... 
            endpoints.exceptionTranslator(webResponseExceptionTranslator); 
            ... 
        } 
        ...
    }
    
    // 1.定义继承OAuth2Exception的异常类
    @JsonSerialize(using = PigAuth2ExceptionSerializer.class)
    public class PigAuth2Exception extends OAuth2Exception {
       @Getter
       private String errorCode;
       public PigAuth2Exception(String msg) {
          super(msg);
       }
       public PigAuth2Exception(String msg, String errorCode) {
          super(msg);
          this.errorCode = errorCode;
       }
    }
    // 2.定义序列化实现类
    public class PigAuth2ExceptionSerializer extends StdSerializer<PigAuth2Exception> {
       public PigAuth2ExceptionSerializer() {
          super(PigAuth2Exception.class);
       }
       @Override
       @SneakyThrows
       public void serialize(PigAuth2Exception value, JsonGenerator gen, SerializerProvider provider) {
          gen.writeStartObject();
          gen.writeObjectField("code", CommonConstants.FAIL);
          gen.writeStringField("msg", value.getMessage());
          gen.writeStringField("data", value.getErrorCode());
          gen.writeEndObject();
       }
    }
    // 3.自定义实现异常转换类
    /**
    * @author lengleng
    * @date 2019/2/1
    * 异常处理,重写oauth 默认实现
    */
    @Slf4j
    public class PigWebResponseExceptionTranslator implements WebResponseExceptionTranslator {
    
       private ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();
       @Override
       @SneakyThrows
       public ResponseEntity<OAuth2Exception> translate(Exception e) {
          // Try to extract a SpringSecurityException from the stacktrace
          Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e);
          Exception ase = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class,
             causeChain);
          if (ase != null) {
             return handleOAuth2Exception(new UnauthorizedException(e.getMessage(), e));
          }
          ase = (AccessDeniedException) throwableAnalyzer
             .getFirstThrowableOfType(AccessDeniedException.class, causeChain);
          if (ase != null) {
             return handleOAuth2Exception(new ForbiddenException(ase.getMessage(), ase));
          }
          ase = (InvalidGrantException) throwableAnalyzer
             .getFirstThrowableOfType(InvalidGrantException.class, causeChain);
          if (ase != null) {
             return handleOAuth2Exception(new InvalidException(ase.getMessage(), ase));
          }
          ase = (HttpRequestMethodNotSupportedException) throwableAnalyzer
             .getFirstThrowableOfType(HttpRequestMethodNotSupportedException.class, causeChain);
          if (ase != null) {
             return handleOAuth2Exception(new MethodNotAllowed(ase.getMessage(), ase));
          }
          ase = (OAuth2Exception) throwableAnalyzer.getFirstThrowableOfType(
             OAuth2Exception.class, causeChain);
          if (ase != null) {
             return handleOAuth2Exception((OAuth2Exception) ase);
          }
          return handleOAuth2Exception(new ServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), e));
       }
       private ResponseEntity<OAuth2Exception> handleOAuth2Exception(OAuth2Exception e) {
          int status = e.getHttpErrorCode();
          HttpHeaders headers = new HttpHeaders();
          headers.set(HttpHeaders.CACHE_CONTROL, "no-store");
          headers.set(HttpHeaders.PRAGMA, "no-cache");
          if (status == HttpStatus.UNAUTHORIZED.value() || (e instanceof InsufficientScopeException)) {
             headers.set(HttpHeaders.WWW_AUTHENTICATE, String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, e.getSummary()));
          }
          // 客户端异常直接返回客户端,不然无法解析
          if (e instanceof ClientAuthenticationException) {
             return new ResponseEntity<>(e, headers,
                HttpStatus.valueOf(status));
          }
          return new ResponseEntity<>(new PigAuth2Exception(e.getMessage(), e.getOAuth2ErrorCode()), headers,
             HttpStatus.valueOf(status));
       }
    }
    4.将自定义异常处理类添加到认证服务器配置
    View Code

    SpringBoot添加定时任务

    // springboot启动添加注解@EnableScheduling
    @EnableScheduling
    public class DemoApplication {
       public static void main(String[] args) {
          SpringApplication.run(DemoApplication.class, args);
       }
    }
    // task
    @Slf4j
    @Component
    public class DemoTask {
       @Autowired
       private XxService xxService;
    
       @Scheduled(cron="0 30 2 * * ? ")
       protected void process(){
          log.info("EbOrderSyncTask同步开始 =========>" + LocalDateTime.now());
          ...
          log.info("EbOrderSyncTask同步结束 =========>" + LocalDateTime.now());
       }
    }
    View Code

    springboot+redis+AOP分布式

    参考网址

    spring-cloud引入swagger

    @Component
    @Primary
    public class DocumentationConfig implements SwaggerResourcesProvider {
       @Override
       public List<SwaggerResource> get() {
          List resources = new ArrayList<>();
          // service-id => xx-appName
          // swagger url => "/admin/v2/api-docs"
          resources.add(swaggerResource("xx-appName", "/admin/v2/api-docs", "2.0"));
          return resources;
       }
       private SwaggerResource swaggerResource(String name, String location, String version) {
          SwaggerResource swaggerResource = new SwaggerResource();
          swaggerResource.setName(name);
          swaggerResource.setLocation(location);
          swaggerResource.setSwaggerVersion(version);
          return swaggerResource;
       }
    }
    
    @Configuration
    @EnableSwagger2
    public class SystemSwaggerConfig extends WebMvcConfigurationSupport {
        @Bean
        public Docket api() {
          return new Docket(DocumentationType.SWAGGER_2)
             .host("128.0.0.1:27000")
             .apiInfo(apiInfo())
             .select()
             // 自行修改为自己的包路径 -> com.xx.controller
             .apis(RequestHandlerSelectors.basePackage("com.xx.controller"))
             .paths(PathSelectors.any())
             .build()
             .globalOperationParameters(getParams());
        }
       private List<Parameter> getParams() {
          //添加head参数start
          ParameterBuilder tokenPar = new ParameterBuilder();
          List<Parameter> pars = new ArrayList<Parameter>();
          tokenPar.name("Authorization").description("令牌").modelRef(new ModelRef("string"))
             .parameterType("header").required(false)
             .defaultValue("Bearer 15265af2-607d-4c8b-ad54-0c434af82849")
             .build();
          pars.add(tokenPar.build());
          return pars;
       }
       @Override
       protected void addResourceHandlers(ResourceHandlerRegistry registry) {
          registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");;
          registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
          super.addResourceHandlers(registry);
       }
        private ApiInfo apiInfo() {
            return new ApiInfoBuilder().title("接口文档").build();
        }
    }
    View Code

    spring-MockMvc请求方式

    // 1.路径请求
    mockMvc.perform(MockMvcRequestBuilders.请求方式("url/{path}",参数值);
                    
    // 2.表单请求
    mockMvc.perform(MockMvcRequestBuilders.请求方式("url").param("","").contentType(MediaType.APPLICATION_FORM_URLENCODED);                
    // 3.JSON请求
    mockMvc.perform(MockMvcRequestBuilders.请求方式,一般为POST("url").content(JSONObject.toJSONString(map)).contentType(.contentType(MediaType.APPLICATION_JSON)); 

    spring-enable-xx注解原理

    [参考网址1]
    [参考网址2]

    所有@Enable* 注解都是有@Import的组合注解,@Enable* 自动开启的实现其实就是导入了一些自动配置的Bean,@Import 注解的最主要功能就是导入额外的配置信息。

    @Import 注解的用法
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Import(SchedulingConfiguration.class)
    @Documented
    public @interface EnableScheduling {
    }
    
    /**
     * 可以看到EnableScheduling注解直接导入配置类SchedulingConfiguration,这个类注解了@Configuration,且注册了一个scheduledAnnotationProcessor的Bean
     */
    @Configuration
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public class SchedulingConfiguration {
        @Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
            return new ScheduledAnnotationBeanPostProcessor();
        }
    }
    View Code
    实现 ImportSelector 接口
    /**
    如果并不确定引入哪个配置类,需要根据@Import注解所标识的类或者另一个注解(通常是注解)里的定义信息选择配置类的话,用这种方式。*/
    // ImportSelector接口只有一个方法:
    String[] selectImports(AnnotationMetadata importingClassMetadata);
    
    /** 注解类 */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(AsyncConfigurationSelector.class)
    public @interface EnableAsync {
        Class<? extends Annotation> annotation() default Annotation.class;
        boolean proxyTargetClass() default false;
        AdviceMode mode() default AdviceMode.PROXY;
        int order() default Ordered.LOWEST_PRECEDENCE;
    }
    
    /**
     * 实现选择器
     * AsyncConfigurationSelector继承AdviceModeImportSelector,AdviceModeImportSelector类实现ImportSelector接口 根据AdviceMode的不同来选择生明不同的Bean
     */
    public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
        private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
                "org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
        @Override
        @Nullable
        public String[] selectImports(AdviceMode adviceMode) {
            switch (adviceMode) {
                case PROXY:
                    return new String[] {ProxyAsyncConfiguration.class.getName()};
                case ASPECTJ:
                    return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
                default:
                    return null;
            }
        }
    }
    View Code
    实现 ImportBeanDefinitionRegistrar接口
    /**
    一般只要用户确切知道哪些Bean需要放入容器的话,自己可以通过spring 提供的注解来标识就可以了,比如@Component,@Service,@Repository,@Bean等。 如果是不确定的类,或者不是spring专用的,所以并不想用spring的注解进行侵入式标识,那么就可以通过@Import注解,实现ImportBeanDefinitionRegistrar接口来动态注册Bean。 比如:
    */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(AspectJAutoProxyRegistrar.class)
    public @interface EnableAspectJAutoProxy {
        boolean proxyTargetClass() default false;
        boolean exposeProxy() default false;
    }
    
    /**
     * AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,ImportBeanDefinitionRegistrar的作用是在运行时自动添加Bean到已有的配置类,通过重写方法:
     */
    AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
            AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata,         EnableAspectJAutoProxy.class);
            if (enableAspectJAutoProxy != null) {
                if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                }
                if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                    AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
                }
            }
        }
    }
    View Code

    springboot自定义日志格式

    <!-- resource/logback-spring.xml -->
    <configuration debug="false" scan="false">
        <springProperty scop="context" name="spring.application.name" source="spring.application.name" defaultValue=""/>
        <property name="log.path" value="logs/${spring.application.name}"/>
        <!-- Console log output -->
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
           <encoder>
              <pattern>${CONSOLE_LOG_PATTERN}</pattern>
           </encoder>
        </appender>
    
        <!-- Log file debug output -->
        <appender name="debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
           <file>${log.path}/debug.log</file>
           <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
              <fileNamePattern>${log.path}/%d{yyyy-MM, aux}/debug.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
              <maxFileSize>50MB</maxFileSize>
              <maxHistory>30</maxHistory>
           </rollingPolicy>
           <encoder>
              <pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
           </encoder>
           <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
               <level>DEBUG</level>
           </filter>
        </appender>
    
        <!-- Log file error output -->
        <appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${log.path}/error.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
               <fileNamePattern>${log.path}/%d{yyyy-MM}/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
               <maxFileSize>50MB</maxFileSize>
               <maxHistory>30</maxHistory>
            </rollingPolicy>
            <encoder>
               <pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
            </encoder>
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                <level>ERROR</level>
            </filter>
        <appender>
    
        <!-- Level: FATAL 0  ERROR 3  WARN 4  INFO 6  DEBUG 7 -->
        <root level="INFO">
            <appender-ref ref="console"/>
            <appender-ref ref="debug"/>
            <appender-ref ref="error"/>
        </root>
    </configuration>
    View Code

    引入springboot-task

    1.启用task配置
    (1) 配置文件的方式:application.properties
    spring.task.scheduling.pool.size=20
    spring.task.scheduling.thread-name-prefix=Job-Thread-
    
    (2) 配置类的方式
    @Configuration
    @EnableScheduling
    @ComponentScan(basePackages = {"com.xkcoding.task.job"})
    public class TaskConfig implements SchedulingConfigurer {
        @Override
        public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
            taskRegistrar.setScheduler(taskExecutor());
        }
        @Bean
        public Executor taskExecutor() {
            return new ScheduledThreadPoolExecutor(20, new BasicThreadFactory.Builder().namingPattern("Job-Thread-%d").build());
        }
    }
    
    2.新增TaskJob类
    @Component
    @Slf4j
    public class TaskJob {
        /**     
         * 按照标准时间来算,每隔 10s 执行一次     
         */
        @Scheduled(cron = "0/10 * * * * ?")
        public void job1() {
            log.info("【job1】开始执行:{}", DateUtil.formatDateTime(new Date()));
        }
        /**     
         * 从启动时间开始,间隔 2s 执行     
         * 固定间隔时间     
         */
        @Scheduled(fixedRate = 2000)
        public void job2() {
            log.info("【job2】开始执行:{}", DateUtil.formatDateTime(new Date()));
        }
        /**     
         * 从启动时间开始,延迟 5s 后间隔 4s 执行     
         * 固定等待时间     
         */
        @Scheduled(fixedDelay = 4000, initialDelay = 5000)
        public void job3() {
            log.info("【job3】开始执行:{}", DateUtil.formatDateTime(new Date()));
        }
    }
    View Code

    spring类的生命周期

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
                http://www.springframework.org/schema/beans 
                http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-3.2.xsd">       
         <bean id="person1" destroy-method="myDestroy" 
                init-method="myInit" class="com.test.spring.life.Person">
            <property name="name">
                <value>jack</value>
            </property>
        </bean>
        <!-- 配置自定义的后置处理器 -->
         <bean id="postProcessor" class="com.pingan.spring.life.MyBeanPostProcessor" />
    </beans>
    
    
    /**
     * 1.实例化Bean对象
     * 2.设置对象属性
     * 3.调用BeanNameAware.setBeanName()
     * 4.调用BeanNameAware.setBeanFactory()
     * 5.调用ApplicationContextAware.setApplicationContext()
     * 6.调用BeanPostProcessor.postProcessBeforeInitialzation() -> 前置处理器
     * 7.调用InitializingBean.afterPropertiesSet()
     * 8.调用init-method方法
     * 9.调用BeanPostProcessor.postProcessAfterInitialization() -> 后置处理器
     * 10.缓存一份Bean实例 -> scope="singleton"
     * 11.容器关闭,调用DisposableBean.destroy()
     * 12.调用自定义的destroy-method
     */
    public class Person implements BeanNameAware, BeanFactoryAware,
            ApplicationContextAware, InitializingBean, DisposableBean {
        private String name;
        public Person() {
            System.out.println("PersonService类构造方法");
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
            System.out.println("set方法被调用");
        }
        //自定义的初始化函数
        public void myInit() {
            System.out.println("myInit被调用");
        }
        //自定义的销毁方法
        public void myDestroy() {
            System.out.println("myDestroy被调用");
        }
        public void destroy() throws Exception {
            // TODO Auto-generated method stub
         System.out.println("destory被调用");
        }
        public void afterPropertiesSet() throws Exception {
            // TODO Auto-generated method stub
            System.out.println("afterPropertiesSet被调用");
        }
        public void setApplicationContext(ApplicationContext applicationContext)
                throws BeansException {
            // TODO Auto-generated method stub
           System.out.println("setApplicationContext被调用");
        }
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            // TODO Auto-generated method stub
             System.out.println("setBeanFactory被调用,beanFactory");
        }
        public void setBeanName(String beanName) {
            // TODO Auto-generated method stub
            System.out.println("setBeanName被调用,beanName:" + beanName);
        }
        public String toString() {
            return "name is :" + name;
        }
    }       
    /** Bean前后置处理器 */
    public class MyBeanPostProcessor implements BeanPostProcessor {
        public Object postProcessBeforeInitialization(Object bean,
                String beanName) throws BeansException {
            // TODO Auto-generated method stub
            
            System.out.println("postProcessBeforeInitialization被调用");
            return bean;
        }
        public Object postProcessAfterInitialization(Object bean,
                String beanName) throws BeansException {
            // TODO Auto-generated method stub
            System.out.println("postProcessAfterInitialization被调用");
            return bean;
        }
    }
    /** 测试类 */
    public class AcPersonServiceTest {
        public static void main(String[] args) {
            System.out.println("开始初始化容器");
            ApplicationContext ac = new ClassPathXmlApplicationContext("com/test/spring/life/applicationContext.xml"); 
            System.out.println("xml加载完毕");
            Person person1 = (Person) ac.getBean("person1");
            System.out.println(person1);        
            System.out.println("关闭容器");
            ((ClassPathXmlApplicationContext)ac).close();
        }
    }
    
    /**
    开始初始化容器
    九月 25, 2016 10:44:50 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
    信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@b4aa453: startup date [Sun Sep 25 22:44:50 CST 2016]; root of context hierarchy
    九月 25, 2016 10:44:50 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
    信息: Loading XML bean definitions from class path resource [com/test/spring/life/applicationContext.xml]
    Person类构造方法
    set方法被调用
    setBeanName被调用,beanName:person1
    setBeanFactory被调用,beanFactory
    setApplicationContext被调用
    postProcessBeforeInitialization被调用
    afterPropertiesSet被调用
    myInit被调用
    postProcessAfterInitialization被调用
    xml加载完毕
    name is :jack
    关闭容器
    九月 25, 2016 10:44:51 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
    信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@b4aa453: startup date [Sun Sep 25 22:44:50 CST 2016]; root of context hierarchy
    destory被调用
    myDestroy被调用
    */
    View Code

    SpringBoot自定义配置文件

    @Data
    @ConfigurationProperties("example.service")
    @Component
    public class WrapServiceProperties {
        private String prefix;
        private String suffix;
    }
    
    <!-- application.properties -->
    example.service.prefix=###
    example.service.suffix=@@@
    View Code

    Springboot-引入xxl-job

    1.部署xx-job-admin服务端
    (1) 下载项目
    $ git clone https://github.com/xuxueli/xxl-job
    (2) 初始化doc/tables-xxl_job.sql脚本
    (3) 启动服务,并验证:
    http://127.0.0.1:8080/xxl-job-admin/
    初始账号密码:admin/123456
    
    2.引入客户端
    (1) 引入jar包(2.2.0版本+服务端2.2.3-SNAPSHOT版本)
    appname:在xxl-job配置的执行器的appname
    accessToken:调度中心通讯TOKEN,与xxl-job-admin配置文件的token一致即可
    <!-- pom.xml -->
    <dependency>
        <groupId>com.xuxueli</groupId>
        <artifactId>xxl-job-core</artifactId>
        <version>2.2.0</version>
    </dependency>
    
    (2) 配置xxl-job服务器
    <!-- application.yml -->
    xxl:
      job:
        admin:
          addresses: http://127.0.0.1:8000/xxl-job-admin
        executor:
          appname: xxl-job-client
          ip:
          port: 9999
          logpath: /logs/xxl-job/jobhandler
          logretentiondays: 30
        accessToken: 6889b70769ffb1e955ba69396f0cca6b
    
    
    (3) 将XxlJobConfig交给spring管理
    @Configuration
    public class XxlJobConfig {
        @Value("${xxl.job.admin.addresses}")
        private String adminAddresses;
        @Value("${xxl.job.executor.appname}")
        private String appName;
        @Value("${xxl.job.executor.ip}")
        private String ip;
        @Value("${xxl.job.executor.port}")
        private int port;
        @Value("${xxl.job.accessToken}")
        private String accessToken;
        @Value("${xxl.job.executor.logpath}")
        private String logPath;
        @Value("${xxl.job.executor.logretentiondays}")
        private int logRetentionDays;
    
        // 2.2.0+版本移除
        //@Bean(initMethod = "start", destroyMethod = "destroy")
        @Bean
        public XxlJobSpringExecutor xxlJobExecutor() {
    //        logger.info(">>>>>>>>>>> xxl-job config init.");
            XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
            xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
            xxlJobSpringExecutor.setAppName(appName);
            xxlJobSpringExecutor.setIp(ip);
            xxlJobSpringExecutor.setPort(port);
            xxlJobSpringExecutor.setAccessToken(accessToken);
            xxlJobSpringExecutor.setLogPath(logPath);
            xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
            return xxlJobSpringExecutor;
        }
    }
    
    
    (4) 写一个定时任务
    /**
     * XxlJob开发示例(Bean模式)
     *
     * 开发步骤:
     * 1、在Spring Bean实例中,开发Job方法,方式格式要求为 "public ReturnT<String> execute(String param)"
     * 2、为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")",注解value值对应的是调度中心新建任务的JobHandler属性的值。
     * 3、执行日志:需要通过 "XxlJobLogger.log" 打印执行日志;
     *
     * @author xuxueli 2019-12-11 21:52:51
     */
    @Component
    @Sl4j
    public class SampleXxlJob {
        /**
         * 1、简单任务示例(Bean模式)
         */
        @XxlJob("demoJobHandler")
        public ReturnT<String> demoJobHandler(String param) throws Exception {
            log.info("XXL-JOB, Hello World.");
    
            for (int i = 0; i < 5; i++) {
             XxlJobLogger.log("beat at:" + i);
                TimeUnit.SECONDS.sleep(2);
         }
            return ReturnT.SUCCESS;
        }
    }    
    
    (5) 在服务端添加刚刚创建的定时任务
    界面输入参数:
    JobHandler:demoJobHandler
    View Code

    Springboot-引入ActiveMQ

    1.引入ActiveMQ支持
    (1) pom.xml
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
    </dependencies>
    (2) application.properties
    spring.activemq.broker-url=tcp://localhost:61616
    spring.activemq.user=admin
    spring.activemq.password=admin
    
    2.写demo
    (1) 消费者-Consumer
    @Component
    @EnableJms
    @Slf4j
    public class ActiveMQListener {
        @JmsListener(destination = "test-queue")
        public void listener(String message) {
            log.info("Message received {} ", message);
        }
    }
    (2) 生产者-Producer
    <!-- JmsConfig.java -->
    package com.test.activemq.configuration;
    import org.apache.activemq.command.ActiveMQQueue;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.jms.annotation.EnableJms;
    import javax.jms.Queue;
    @Configuration
    public class JmsConfig {
        @Bean
        public Queue queue(){
            return new ActiveMQQueue("test-queue");
        }
    }
    <!-- Producer.java -->
    package com.test.activemq.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import javax.jms.Queue;
    
    @RestController
    @RequestMapping("/api")
    public class MessageController {
        @Autowired
        private Queue queue;
        @Autowired
        private JmsTemplate jmsTemplate;
        @GetMapping("message/{message}")
        public ResponseEntity<String> publish(@PathVariable("message") final String message){
            jmsTemplate.convertAndSend(queue, message);
            return new ResponseEntity(message, HttpStatus.OK);
        }
    }
    View Code

    springboot引入动态quartz

    package com.line.demo.task;
    import java.util.Arrays;
    import java.util.List;
    /**
     * @author: cent
     * @email: 292462859@qq.com
     * @date: 2019/1/16.
     * @description:
     */
    @Configuration
    @EnableScheduling
    @Slf4j
    public class DynamicSchedule implements SchedulingConfigurer {    
        /**
         * 测试数据,实际可从数据库获取
         */
        private List<Task> tasks = Arrays.asList(            
            new Task(1, "任务1", "*/30 * * * * *"),            
            new Task(2, "任务2", "*/30 * * * * *"),            
            new Task(3, "任务3", "*/30 * * * * *"),            
            new Task(4, "任务4", "*/30 * * * * *"),            
            new Task(5, "任务5", "*/30 * * * * *"),            
            new Task(6, "任务6", "*/30 * * * * *"),            
            new Task(7, "任务7", "*/30 * * * * *"),            
            new Task(8, "任务8", "*/30 * * * * *"),            
            new Task(9, "任务9", "*/30 * * * * *"),            
            new Task(10, "任务10", "*/30 * * * * *")
        );
        @Override
        public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
            tasks.forEach(task -> {            
                //任务执行线程
                Runnable runnable = () -> log.info("execute task {}", task.getId());            
                //任务触发器
                Trigger trigger = triggerContext -> {                
                    //获取定时触发器,这里可以每次从数据库获取最新记录,更新触发器,实现定时间隔的动态调整
                    CronTrigger cronTrigger = new CronTrigger(task.getCron());                
                    return cronTrigger.nextExecutionTime(triggerContext);
                };           
                //注册任务
                scheduledTaskRegistrar.addTriggerTask(runnable, trigger);
            });
        }    
        
        @Data
        @AllArgsConstructor
        static class Task {        /**
             * 主键ID
             */
            private int id;        /**
             * 任务名称
             */
            private String name;        /**
             * cron表达式
             */
            private String cron;
        }
    }
    View Code

    springboot配置全局异常

    @Slf4j
    @RestControllerAdvice
    public class GlobalExceptionHandler {
        /**
         * 全局异常.
         *
         * @param e the e
         * @return R
         */
        @ExceptionHandler(Exception.class)
        @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        public R exception(Exception e) {
            log.error("全局异常信息 ex={}", e.getMessage(), e);
            return R.failed(e);
        }
    
        /**
         * validation Exception
         *
         * @param exception
         * @return R
         */
        @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public R bodyValidExceptionHandler(MethodArgumentNotValidException exception) {
            List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
            log.warn(fieldErrors.get(0).getDefaultMessage());
            return R.failed(fieldErrors.get(0).getDefaultMessage());
        }
    
        /**
         * 处理所有业务异常
         *
         * @param e
         * @return
         */
        @ExceptionHandler(BusinessException.class)
        public R handleBusinessException(BusinessException e) {
            log.error("业务异常异常信息 ex={}", e.getMessage(), e);
            return R.failed(e);
        }
    }
    
    @NoArgsConstructor
    public class BusinessException extends RuntimeException {
        private static final long serialVersionUID = 1L;
        public BusinessException(String message) {
            super(message);
        }
        public BusinessException(Throwable cause) {
            super(cause);
        }
        public BusinessException(String message, Throwable cause) {
            super(message, cause);
        }
        public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
            super(message, cause, enableSuppression, writableStackTrace);
        }
    }
    
    /**
     * 响应信息主体
     *
     * @param <T>
     * @author xw
     */
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Accessors(chain = true)
    public class R<T> implements Serializable {
        private static final long serialVersionUID = 1L;
        @Getter
        @Setter
        private int code;
        @Getter
        @Setter
        private String msg;
        @Getter
        @Setter
        private T data;
    
        public static <T> R<T> ok() {
            return restResult(null, CommonConstants.SUCCESS, null);
        }
        public static <T> R<T> ok(T data) {
            return restResult(data, CommonConstants.SUCCESS, null);
        }
        public static <T> R<T> ok(T data, String msg) {
            return restResult(data, CommonConstants.SUCCESS, msg);
        }
        public static <T> R<T> failed() {
            return restResult(null, CommonConstants.FAIL, null);
        }
        public static <T> R<T> failed(String msg) {
            return restResult(null, CommonConstants.FAIL, msg);
        }
        public static <T> R<T> failed(T data) {
            return restResult(data, CommonConstants.FAIL, null);
        }
        public static <T> R<T> failed(T data, String msg) {
            return restResult(data, CommonConstants.FAIL, msg);
        }
        private static <T> R<T> restResult(T data, int code, String msg) {
            R<T> apiResult = new R<>();
            apiResult.setCode(code);
            apiResult.setData(data);
            apiResult.setMsg(msg);
            return apiResult;
        }
    }
    View Code

    spring获取某个类的所有子类

    String[] beanNamesForType = SpringContextHolder.getApplicationContext().getBeanNamesForType(AbstractObserver.class);

    spring-feign传多个参数

    @FeignClient(name = "microservice-provider-user")
    public interface UserFeignClient {
      @RequestMapping(value = "/get", method = RequestMethod.GET)
      public User get1(@RequestParam("id") Long id, @RequestParam("username") String username);
    }
    
    @FeignClient(name = "microservice-provider-user")
    public interface UserFeignClient {
      @RequestMapping(value = "/get", method = RequestMethod.GET)
      public User get2(@RequestParam Map<String, Object> map);
    }
    
    @RestController
    public class UserController {
      @PostMapping("/post")
      public User post(@RequestBody User user) {
        ...
      }
    }
    
    @FeignClient(name = "microservice-provider-user")
    public interface UserFeignClient {
      @RequestMapping(value = "/post", method = RequestMethod.POST)
      public User post(@RequestBody User user);
    }
    View Code

    Mysql

    初始化数据库、用户

    使用root账号创建数据库db_name并授权给test账号
    $ mysql -uroot -h0 -P3306 -p123456
    $ create database db_name;
    $ grant all privileges on db_name.* to test@'localhost' identified by '123456';
    $ grant all privileges on db_name.* to test@'127.0.0.1' identified by '123456';

    导出数据库和表

    -- 导出db_name整个数据库
    mysqldump -u test -p123456 db_name -P 3306 > db_name.sql
    
    -- 导出某数据库指定的表(db_name.table_name)
    mysqldump -u test -p123456 db_name table_name > table_name.sql

    导入sql脚本

    $ mysql -u test -p123456 db_name < /opt/sql/xx.sql

    添加索引

    -- 添加PRIMARY KEY(主键索引)
    ALTER TABLE `table_name` ADD PRIMARY KEY index_name( `column` )
    -- 添加UNIQUE(唯一索引)
    ALTER TABLE `table_name` ADD UNIQUE index_name( `column` ) 
    -- 添加INDEX(普通索引)
    ALTER TABLE `table_name` ADD INDEX index_name ( `column` )
    -- 添加FULLTEXT(全文索引)
    ALTER TABLE `table_name` ADD FULLTEXT ( `column`)  
    -- 添加多列索引
    ALTER TABLE `table_name` ADD INDEX index_name ( `column1`, `column2`, `column3` )
    
    -- 删除索引
    drop index index_name on table_name ;
    View Code

    修改表字段

    -- 添加表的字段 alter table 表名  add  字段名  字段的类型
    alter table table1 add transactor varchar(10) not Null;
    -- 修改表的字段类型   ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型定义;
    ALTER TABLE chatter_users MODIFY COLUMN ip VARCHAR(50);
    -- 修改表的字段名    alter table 表名 change 原字段名  新字段名  字段的类型
    alter table student change physics physisc char(10) not null;
    
    -- 删除表的字段    alter table 表名 drop column 字段名
    alter table `user_movement_log` drop column Gatewayid;
    -- 调整表的顺序:
    ALTER TABLE `user_movement_log` CHANGE `GatewayId` `GatewayId` int not null default 0 AFTER RegionID
    -- 表的重命名   alter table 原表名 rename 现表名;
    alter table t1 rename t2;
    -- 删除表的数据   
    delete from 表名  where  (条件)    id 不是从1开始;
    truncate table 表名     id是从1 开始的;
    -- 创建表的例子  
    CREATE TABLE hlh_message (
        id int(11) NOT NULL AUTO_INCREMENT COMMENT '健康表id',
        title varchar(40) NOT NULL COMMENT '健康标题',
        hlh_url text DEFAULT NULL COMMENT '图片地址',
        bewrite VARCHAR(350) NOT NULL COMMENT '描述',
        content VARCHAR(350) NOT NULL COMMENT '内容',
        type tinyint(1) NOT NULL DEFAULT '0' COMMENT '健康知识 0 健康咨询 1',
        create_time date DEFAULT NULL COMMENT '发布消息的时间',
        PRIMARY KEY (id)
    )ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='健康表';
    View Code

    Mysql日期操作

    -- mysql日期格式化
    DATE_FORMAT( created_date, "%Y-%m-%d")

    常用查询

    -- mysql查询奇偶行
    set @row = 0;
    select id from (select (@row:=case when @row is null then 1 else @row+1 end) as RNr, a.id,a.order_no,a.sku,a.send_count,b.count from cg_supplier_shipping_order_detail a 
    inner join cg_buyer_purchase_order b on a.buyer_purchase_order_order_no=b.order_no and a.sku=b.sku where b.order_no='PO119092540003' and b.send_total>b.count) t where t.RNr%2 = 0; -- 查看慢sql show variables like '%query%';

    查看mysql表结构和表创建语句

    -- 查看所有表
    show tables;
    -- 查看表结构
    desc sys_log;
    -- 查看建表语句
    show create table tablename;

    mysql慢sql查询

    -- show processlist;
    -- show variables like '%tmp%';
    -- show variables like '%query%';

    Mybatis

    Mybatis-数据权限

    // 使用方法
    public interface XxMapper extends BaseMapper<Xx> {
        // dataScope--数据权限载体
        IPage<Xx> getXxPage(Page page, @Param("xx") Xx xx,@Param("dataScope") DataScope dataScope);
    }
    @Data
    @EqualsAndHashCode(callSuper = true)
    public class DataScope extends HashMap {
        /**
         * 限制范围的字段名称
         */
        private String firstScopeName = "warehouse_id";
        /**
         * 具体的数据范围
         */
        private List<Integer> firstIds;
        /**
         * 是否只查询本部门
         */
        private Boolean isOnly = false;
        ...
    }
    
    /**
     * @author admin
     * @date 2019/2/1
     */
    @Configuration
    @MapperScan("com.demo.mapper")
    public class MybatisPlusConfigurer {
        /**
         * 分页插件
         *
         * @return PaginationInterceptor
         */
        @Bean
        public PaginationInterceptor paginationInterceptor() {
            return new PaginationInterceptor().setLimit(10000);
        }
        /**
         * 数据权限插件
         *
         * @return DataScopeInterceptor
         */
        @Bean
        public DataScopeInterceptor dataScopeInterceptor() {
            return new DataScopeInterceptor();
        }
        /**
         * 逻辑删除
         *
         * @return
         */
        @Bean
        public ISqlInjector sqlInjector() {
            return new LogicSqlInjector();
        }
    }
    
    /**
     * @author xw
     * @date 2019/7/30
     * <p>
     * mybatis 数据权限拦截器
     */
    @Slf4j
    @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
    public class DataScopeInterceptor extends AbstractSqlParserHandler implements Interceptor {
    
        @Override
        @SneakyThrows
        public Object intercept(Invocation invocation) {
            StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget());
            MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
            this.sqlParser(metaObject);
            // 先判断是不是SELECT操作
            MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
            if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
                return invocation.proceed();
            }
    
            BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
            String originalSql = boundSql.getSql();
            Object parameterObject = boundSql.getParameterObject();
    
            //查找参数中包含DataScope类型的参数
            DataScope dataScope = findDataScopeObject(parameterObject);
            if (dataScope == null) {
                return invocation.proceed();
            } else {
                // 数据权限规则 仓库id+平台id
                StringBuilder sb = new StringBuilder(" where 1=1 ");
                // 第一个范围
                String firstScopeName = dataScope.getFirstScopeName();
                List<Integer> firstIds = dataScope.getFirstIds();
                if (StrUtil.isNotBlank(firstScopeName) && CollectionUtil.isNotEmpty(firstIds) && firstIds.size() >= 1) {
                    sb.append(String.format(" and temp_data_scope.%s in (%s)", firstScopeName, CollectionUtil.join(firstIds, ",")));
                }
                // 第二个范围(平台权限,当数据平台id为null时,默认所有人可见)
                String secondScopeName = dataScope.getSecondScopeName();
                List<Integer> secondIds = dataScope.getSecondIds();
                if (StrUtil.isNotBlank(secondScopeName) && CollectionUtil.isNotEmpty(secondIds) && secondIds.size() >= 1) {
                    sb.append(String.format(" and (temp_data_scope.%s in (%s) or temp_data_scope.%s is null)", secondScopeName, CollectionUtil.join(secondIds, ","), secondScopeName));
                }
                originalSql = "select * from (" + originalSql + ") temp_data_scope" + sb.toString();
                metaObject.setValue("delegate.boundSql.sql", originalSql);
                return invocation.proceed();
            }
        }
        /**
         * 生成拦截对象的代理
         *
         * @param target 目标对象
         * @return 代理对象
         */
        @Override
        public Object plugin(Object target) {
            if (target instanceof StatementHandler) {
                return Plugin.wrap(target, this);
            }
            return target;
        }
        /**
         * mybatis配置的属性
         *
         * @param properties mybatis配置的属性
         */
        @Override
        public void setProperties(Properties properties) {
    
        }
        /**
         * 查找参数是否包括DataScope对象
         *
         * @param parameterObj 参数列表
         * @return DataScope
         */
        private DataScope findDataScopeObject(Object parameterObj) {
            if (parameterObj instanceof DataScope) {
                return (DataScope) parameterObj;
            } else if (parameterObj instanceof Map) {
                for (Object val : ((Map<?, ?>) parameterObj).values()) {
                    // { param0:xx, param1:xx, xxBean:xx: ...}
                    if (val instanceof DataScope) {
                        return (DataScope) val;
                    }
                }
            }
            return null;
        }
    }
    View Code

    MybatisPlus-公共类

    /**
     * BaseEntity
     *
     * @author xw
     * @date 2020/5/6
     */
    public class BaseEntity<T extends Model<?>> extends Model<T> {
        @ApiModelProperty("创建时间")
        private LocalDateTime createTime;
        @ApiModelProperty("创建人")
        private Integer createUser;
        @ApiModelProperty("更新时间")
        private LocalDateTime updateTime;
        @ApiModelProperty("更新人")
        private Integer updateUser;
        @ApiModelProperty(value = "删除标识:1-删除,0-正常,默认为0")
        private Integer delFlag;
        
        // setter、getter
    }
    
    /**
     * BaseServiceImpl
     *
     * @author xw
     * @date 2020/5/6
     */
    public class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseEntity> extends ServiceImpl<M, T> {
        @Override
        public boolean save(T entity) {
            entity.setCreateUser(UserUtils.getCurrentUserId());
            entity.setCreateTime(LocalDateTime.now());
            return super.save(entity);
        }
        @Override
        public boolean saveBatch(Collection<T> entityList, int batchSize) {
            if (CollectionUtil.isNotEmpty(entityList)) {
                entityList.stream().forEach(m -> {
                    m.setCreateUser(UserUtils.getCurrentUserId());
                    m.setCreateTime(LocalDateTime.now());
                });
            }
            return super.saveBatch(entityList, batchSize);
        }
        @Override
        public boolean updateById(T entity) {
            entity.setUpdateUser(UserUtils.getCurrentUserId());
            entity.setUpdateTime(LocalDateTime.now());
            return super.updateById(entity);
        }
        @Override
        public boolean updateBatchById(Collection<T> entityList, int batchSize) {
            if (CollectionUtil.isNotEmpty(entityList)) {
                entityList.stream().forEach(m -> {
                    m.setUpdateUser(UserUtils.getCurrentUserId());
                    m.setUpdateTime(LocalDateTime.now());
                });
            }
            return super.updateBatchById(entityList, batchSize);
        }
    }
    View Code

    MybatisPlus常用注解

    /**example
     * 删除时 update user set deleted=1 where id =1 and deleted=0
     * 查找时 select * from user where deleted=0
     */
    @TableLogic
    private Integer deleted;
    
    // 忽略实体bean非数据库字段
    @TableField(exist=false) 
    
    // 新增、修改值为null字段
    @TableField(fill = FieldFill.INSERT_UPDATE)
    View Code

    MybatisPlus lamba表达式使用

    $condition = Wrappers.<~>query().lambda().eq(SysUserRole::getRoleId, 5);
    xxService.list($condition)
    xxService.getOne($condition)
    ...
    View Code

    MybatisPlus分页

    public Page<T> selectPage(Page<T> page, EntityWrapper<T> entityWrapper) { 
        if (null != entityWrapper) { 
            entityWrapper.orderBy(page.getOrderByField(), page.isAsc()); 
        } 
        page.setRecords(baseMapper.selectPage(page, entityWrapper)); 
        return page; 
    }
    View Code

    MybatisPlus拼原生

    EntityWrapper<User> ew = new EntityWrapper<User>();
    ew.setEntity(new User(1)); 
    ew.where("user_name={0}", "'zhangsan'").and("id=1") 
        .orNew("user_status={0}", "0").or("status=1") 
        .notLike("user_nickname", "notvalue") 
        .andNew("new=xx").like("hhh", "ddd") 
        .andNew("pwd=11").isNotNull("n1,n2").isNull("n3") 
        .groupBy("x1").groupBy("x2,x3") 
        .having("x1=11").having("x3=433") 
        .orderBy("dd").orderBy("d1,d2"); 
    System.out.println(ew.getSqlSegment());
    View Code

    MybatisPlus自定义sql

    List<User> selectMyPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper);
    <select id="selectMyPage" resultType="User"> 
        SELECT * FROM user 
        <where> 
            ${ew.sqlSegment} 
        </where> 
    </select>
    View Code

    Mybatis-like

    <if test="xx.name != null and xx.name != ''">
        AND name like CONCAT('%',#{xx.name},'%')
    </if>
    View Code

    MybatisPlus-update

    // 方式一
    CkQcOrderInfo qcOrderInfo = this.getById(qcOrderDetail.getQcOrderId());
    this.update(Wrappers.<CkQcOrderInfo>lambdaUpdate()
                .eq(CkQcOrderInfo::getId, qcOrderDetail.getQcOrderId())
                .set(CkQcOrderInfo::getQcQty, NumUtils.add(qcOrderInfo.getQcQty(), qcOrderDetail.getQcQty()))
                .set(CkQcOrderInfo::getPassQty, NumUtils.add(qcOrderInfo.getPassQty(), qcOrderDetail.getPassQty())));
    
    // 方式二
    CkQcOrderInfo qcOrderInfo = this.getById(qcOrderDetail.getQcOrderId());
    qcOrderInfo.setQcQty(NumUtils.add(qcOrderInfo.getQcQty(), qcOrderDetail.getQcQty()));
    qcOrderInfo.setPassQty(NumUtils.add(qcOrderInfo.getPassQty(), qcOrderDetail.getPassQty()));
    this.updateById(qcOrderInfo);
    @Override
    public boolean updateById(CkQcOrderInfo entity) {
        entity.setUpdateUser(UserUtils.getCurrentUserId());
        entity.setUpdateTime(LocalDateTime.now());
        return super.updateById(entity);
    }
    View Code

    Mybatis-in

    <select id="getSimilarity" parameterType="java.util.HashMap" resultType="java.util.HashMap">
        select * from table
        where ids in 
        <foreach item="item" index="index" collection="ids.split(',')"  open="(" separator="," close=")">
                    #{item}
        </foreach>
      </select>
    View Code

    Mybatis-time-between

    <if test="xx.startTime != null">
        AND create_time &gt;= #{xx.startTime}
    </if>
    <if test="xx.endTime != null">
        AND create_time &lt;= #{xx.endTime}
    </if>
    View Code

    其它

    Idea代码模板

    // 1.toPageVo -- $beanName$从clipboard()获取
    private IPage<$beanName$VO> toPageVo(IPage<$beanName$> page) {
        return new Page<$beanName$VO>(page.getCurrent(), page.getSize(), page.getTotal())
            .setRecords(page.getRecords().stream().map(m -> beanToVo(m)).collect(Collectors.toList()));
    }
    private $beanName$VO beanToVo($beanName$ m) {
        if (Objects.isNull(m)) {
            return null;
        }
        $beanName$VO vo = new $beanName$VO();
        BeanUtils.copyProperties(m, vo);
        $END$
        return vo;
    }
    // 2.ifeq:判断相等
    if (Objects.equals($v1$, $v2$)) {
        $END$
    }
    // 3.ifn:判断空
    if (Objects.isNull($VAR$)) {
        $END$
    }
    // 4.pstr:private String
    /**
     * $desc$
     */
    @ApiModelProperty(value = "$desc$")
    private String $v$;
    $END$
    // 5.psdate
    /**
     * 起始时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty(value = "起始时间")
    private LocalDateTime $END$startTime;
    // 6.pedate
    /**
     * 结束时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty(value = "结束时间")
    private LocalDateTime $END$endTime;
    // 7.plist
    /**
     * $desc$
     */
    @ApiModelProperty(value = "$desc$")
    private List<$type$> items;
    $END$
    // 8.tcc
    try {
        $END$
    } catch(Exception e) {
        e.printStackTrace();
    }
    View Code

    hutool工具类

    官网

    JDK8常规操作

    public class Apple {
        private Integer id;
        private String name;
        private BigDecimal money;
        private Integer num;
        public Apple(Integer id, String name, BigDecimal money, Integer num) {
            this.id = id;
            this.name = name;
            this.money = money;
            this.num = num;
        }
    }
    
    // 测试数据
    List<Apple> appleList = new ArrayList<>();//存放apple对象集合
    Apple apple1 =  new Apple(1,"苹果1",new BigDecimal("3.25"),10);
    Apple apple12 = new Apple(1,"苹果2",new BigDecimal("1.35"),20);
    Apple apple2 =  new Apple(2,"香蕉",new BigDecimal("2.89"),30);
    Apple apple3 =  new Apple(3,"荔枝",new BigDecimal("9.99"),40);
    appleList.add(apple1);
    appleList.add(apple12);
    appleList.add(apple2);
    appleList.add(apple3);
    
    //1.List转Map
    /**
    * List -> Map
    * 需要注意的是:
    * toMap 如果集合对象有重复的key,会报错Duplicate key ....
    *  apple1,apple12的id都为1。
    *  可以用 (k1,k2)->k1 来设置,如果有重复的key,则保留key1,舍弃key2
    */
    Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1,k2)->k1));
    
    //2.分组
    //List 以ID分组 Map<Integer,List<Apple>>
    Map<Integer, List<Apple>> groupBy = appleList.stream().collect(Collectors.groupingBy(Apple::getId));
    
    System.err.println("groupBy:"+groupBy);
    {1=[Apple{id=1, name='苹果1', money=3.25, num=10}, Apple{id=1, name='苹果2', money=1.35, num=20}], 2=[Apple{id=2, name='香蕉', money=2.89, num=30}], 3=[Apple{id=3, name='荔枝', money=9.99, num=40}]}
    
    //3.过滤filter
    //过滤出符合条件的数据
    List<Apple> filterList = appleList.stream().filter(a -> a.getName().equals("香蕉")).collect(Collectors.toList());
    
    System.err.println("filterList:"+filterList);
    [Apple{id=2, name='香蕉', money=2.89, num=30}]
    
    //4.求和
    //计算 总金额
    BigDecimal totalMoney = appleList.stream().map(Apple::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
    System.err.println("totalMoney:"+totalMoney);  //totalMoney:17.48
    
    //计算 数量int sum = appleList.stream().mapToInt(Apple::getNum).sum();
    System.err.println("sum:"+sum);  //sum:100
    
    // 5.stream下标问题
    AtomicInteger sort = new AtomicInteger(1);
    list = list.stream().map(m -> {
        m.setImgSort(sort.get());
        sort.incrementAndGet();
        return m;
    }).collect(Collectors.toList());
    
    // 6.LocalDate常用
    LocalDate date = LocalDate.of(2014, 3, 18);
    DayOfWeek dow = date.getDayOfWeek(); // -》TUESDAY
    int len = date.lengthOfMonth(); // -》31
    boolean leap = date.isLeapYear(); // -》false (not a leap year)
    
    LocalTime time = LocalTime.of(13, 45, 20); //-》13:45:20
    LocalTime time = LocalTime.parse("13:45:20");
    LocalDate date1 = dt1.toLocalDate();
    LocalTime time1 = dt1.toLocalTime();
    
    // Date转LocalDateTime
    Date date = new Date();
    LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    
    // 相差天数
    long days = ChronoUnit.DAYS.between(LocalDate.of(2014, 3, 8), LocalDate.of(2014, 4, 18));
    
    // 日期比较 isBefore、isAfter
    LocalDate t1 = LocalDate.of(2020, 2, 1);
    LocalDate t2 = LocalDate.of(2020, 3, 2);
    System.out.println(t1.isBefore(t2) + t1.isAfter(t2));
    
    // LocalDateTime GET方式请求数据如何接收
    /** 结算起始时间 */
    @ApiModelProperty(value = "结算起始时间")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime startTime;
    /** 结算结束时间 */
    @ApiModelProperty(value = "结算结束时间")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime endTime;
    
    // 当月第一天、最后一天
    LocalDateTime date = LocalDateTime.now();
    LocalDateTime firstday = date.with(TemporalAdjusters.firstDayOfMonth());
    LocalDateTime lastDay = date.with(TemporalAdjusters.lastDayOfMonth());
    System.out.println(“firstday:” + firstday);
    System.out.println(“lastDay:” + lastDay);
    View Code

    常用正则工具类

    /**
     * 1.按正则匹配字符串某一个子串
     */
    // "@pms.hasPermission('cg_cgshiperrorder_edit')" -> cg_cgshiperrorder_edit
    private final static Pattern pattern = Pattern.compile("@pms.hasPermission\('(.*?)'\)");
    private static String getPermission(String str) {
        Matcher m = pattern.matcher(str);
        String result = null;
        while (m.find()) {
            result = m.group(1);
            break;
        }
        return result;
    }
    
    // 2.否定先行断言 (?!pattern)
    // a(?!b) -> 匹配后面不是跟着 "b" 的 "a"
        
    // 3.指定正则表达式的模式
    // (?i) -> 使正则忽略大小写
    // (?s) -> 使正则的 . 匹配所有字符,包括换行符。
    // (?m) -> 使正则的 ^ 和 $ 匹配字符串中每行的开始和结束。
    
    // 4.横向匹配
    var regex = /a[123]b/g;
    var string = "a0b a1b a2b a3b a4b";
    console.log( string.match(regex) ); // ["a1b", "a2b", "a3b"]
    
    // 5.纵向模糊匹配
    var regex = /a[123]b/g;
    var string = "a0b a1b a2b a3b a4b";
    console.log( string.match(regex) ); // ["a1b", "a2b", "a3b"]
    
    // 6.范围[123456abcdefGHIJKLM] -> [1-6a-fG-M]
    // 因为连字符有特殊用途,那么要匹配“a”、“-”、“z”这三者中任意一个字符 -> [-az]或[az-]或[a-z]
    
    // 7.排除字符组 [^abc] -> 某位字符可以是任何东西,但就不能是"a"、"b"、"c"
    
    // 8.常见的简写形式
    // d -> [0-9] 数字
    // D -> [^0-9] 非数字
    // w -> [0-9a-zA-Z_] 单词
    // W -> [^0-9a-zA-Z_] 非单词
    // s -> [ 	v
    
    f] 空白
    // S -> [^ 	v
    
    f] 非空白
    // . -> [^
    
    u2028u2029] 通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。
    // 匹配任意字符 [dD]、[wW]、[sS]、和[^]中任何的一个
    
    // 9.量词
    // {m,} -> 至少出现m次
    // {m} -> 出现m次
    // ? -> 0或1次
    // + -> 至少出现1次
    // * -> 出现任意次,有可能不出现
    View Code

    Junit测试

    (1) 常用测试

    // 1.正常测试
    @Test
    public void test_detail() {
        CkQcOrderInfoDetailVO vo = ckQcOrderInfoService.getDetailById(1L);
        assertTrue("成功", Objects.isNull(vo.getId()));
    }
    
    // 2.异常测试
    @Test
    public void test_qc() {
        try {
            CkQcOrderDetailDTO qcOrderDetail = new CkQcOrderDetailDTO();
            qcOrderDetail.setQcOrderId(1L);
            qcOrderDetail.setQcQty(5);
            qcOrderDetail.setPassQty(5);
            ckQcOrderInfoService.qc(qcOrderDetail);
        } catch (IllegalArgumentException e) {
            assertThat(e.getMessage(), containsString("单号不存在或已删除!"));
        }
        fail("单号不存在或已删除!");
    }

    (2) springboot test

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = DemoApplication.class)
    @AutoConfigureMockMvc
    @Slf4j
    //@Transactional
    public class BaseTest {
        @Autowired
        private WebApplicationContext context;
    
        protected MockMvc mockMvc;
    
        @Before
        public void setup() {
            mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .build();
        }
    
    }

    (3) REST接口测试

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = DemoApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    @AutoConfigureMockMvc
    @Slf4j
    public class OAuthMvcTest {
    
        protected HttpMethod GET = HttpMethod.GET;
        protected HttpMethod POST = HttpMethod.POST;
        protected HttpMethod PUT = HttpMethod.PUT;
        protected HttpMethod DELETE = HttpMethod.DELETE;
    
        @Autowired
        private TestRestTemplate restTemplate;
        final static String API_URL = "http://localhost:9999/admin";
        protected static String USRE_NAME = "admin";
        protected static String PASSWORD = "123456";
    
        @Before
        public void setup() {
        }
    
        @Test
        public void test_access_token_then200() {
            String token = obtainAccessToken("admin", "123456");
            log.info("access_token->{}", token);
        }
    
        protected String execute(String requestControllerMethodPath, HttpMethod method, Object param) {
            return execute(requestControllerMethodPath, method, param, String.class);
        }
    
        /**
         * 执行测试用例
         * @param requestControllerMethodPath controller+method请求路径
         * @param method HttpMethod.GET|POST|PUT|DELETE
         * @param param 请求参数,controller里面的对象
         */
        protected <T> T execute(String requestControllerMethodPath, HttpMethod method, Object param, Class<T> clazz) {
            return execute(requestControllerMethodPath, method, param, USRE_NAME, PASSWORD, clazz);
        }
    
        /**
         * 执行测试用例
         * @param requestControllerMethodPath controller+method请求路径
         * @param method HttpMethod.GET|POST|PUT|DELETE
         * @param param 请求参数,controller里面的对象
         * @param username 用户名
         * @param password 密码
         */
        protected <T> T execute(String requestControllerMethodPath, HttpMethod method, Object param, String username, String password, Class<T> clazz) {
            if (!requestControllerMethodPath.startsWith("/")) {
                requestControllerMethodPath = "/" + requestControllerMethodPath;
            }
            HttpHeaders headers = new HttpHeaders();
            headers.set(HttpHeaders.AUTHORIZATION, OAuth2AccessToken.BEARER_TYPE + " " + obtainAccessToken(username, password));
            HttpEntity entity = new HttpEntity<>(param, headers);
            String endpoint = API_URL + requestControllerMethodPath;
            log.info("request->{}" + entity);
            ResponseEntity responseEntity = restTemplate.exchange(endpoint, method, entity, clazz);
            log.info("body->{}", responseEntity.getBody());
            TestCase.assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
            if (null == responseEntity.getBody()) {
                return null;
            }
            return (T) responseEntity.getBody();
        }
    
        /**
         * 获取登录token
         * @param username 用户名
         * @param password 密码
         * @return
         */
        protected String obtainAccessToken(String username, String password) {
            return obtainAccessInfo(username, password).getStr("access_token");
        }
    
        protected JSONObject obtainAccessInfo(String username, String password) {
            HttpHeaders headers = new HttpHeaders();
            headers.set(HttpHeaders.AUTHORIZATION, "Basic dGVzdDp0ZXN0");
            HttpEntity entity = new HttpEntity<>(null, headers);
            String endpoint = "http://localhost:9999/auth/oauth/token?username="+ username + "&password="+ password +"&randomStr=77371563933589077&code=dw2m&grant_type=password&scope=server";
            ResponseEntity responseEntity = restTemplate.exchange(endpoint, HttpMethod.POST, entity, String.class);
            log.info("token->{}", responseEntity.getBody());
            assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
            JSONObject userInfo = JSONUtil.parseObj(responseEntity.getBody());
            return userInfo;
        }
    }
  • 相关阅读:
    子集和的另外一个问题
    LCS
    表达式求值
    Singleton in java
    自绘ListBox的两种效果
    动态创建、压缩Access数据库(*.MDB)
    C# 中用stopwatch测试代码运行时间
    MVC学习笔记之数据传递
    ATM应用实现
    html的基本语法
  • 原文地址:https://www.cnblogs.com/ice-line/p/13259859.html
Copyright © 2020-2023  润新知