安装

archlinux 安装启动

  • yaourt -S rabbitmq
  • systemctl start rabbitmq.service
  • 测试服务启动
    • rabbitmqctl status
  • 安装管理客户端

centos(阿里ecs)

配置

增加用户并授权

  1. rabbitmqctl adduser admin 123456 # 增加用户并设置用户名密码
  2. rabbitmqctl setusertags admin administrator # 授权
  3. rabbitmqctl setpermissions -p / admin '.*' '.*' '.*' #
    不知道干啥的但是需要不然访问不了

常用操作

相关概念

通常我们谈到队列服务, 会有三个概念: 发消息者、队列、收消息者,RabbitMQ
在这个基本概念之上, 多做了一层抽象, 在发消息者和 队列之间, 加入了交换器
(Exchange). 这样发消息者和队列就没有直接联系,
转而变成发消息者把消息给交换器, 交换器根据调度策略再把消息再给队列。

虚拟主机

一个虚拟主机持有一组交换机、队列和绑定。为什么需要多个虚拟主机呢?很简单,
RabbitMQ 当中,用户只能在虚拟主机的粒度进行权限控制。
因此,如果需要禁止A组访问B组的交换机/队列/绑定,必须为A和B分别创建一个虚拟主机。每一个
RabbitMQ 服务器都有一个默认的虚拟主机”/“。

交换机(Exchange)

交换机的功能主要是接收消息并且转发到绑定的队列,交换机不存储消息,在启用ack模式后,交换机找不到队列会返回错误。交换机有四种类型:Direct,
topic, Headers and Fanout Direct:direct 类型的行为是”先匹配, 再投送”.
即在绑定时设定一个 routingkey, 消息的routingkey 匹配时,
才会被交换器投送到绑定的队列中去, 默认方式
Topic:按规则转发消息(最灵活), 主要通过通配符 Headers:设置 header
attribute 参数类型的交换机 Fanout:转发消息到所有绑定队列

springboot整合

redirexchange 默认

  1. 引入依赖

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
  2. 配置rabbit地址, application.yaml

    1
    2
    3
    4
    5
    6
    7
    spring:
    rabbitmq:
    host: localhost
    password: guest
    port: 5672
    username: guest

  3. 增加queue配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @Configuration
    public class RabbitConfig {

    /**
    * 创建一个叫hello的queue
    * @return
    */
    @Bean
    public Queue queue(){
    return new Queue("ttang");
    }
    }

  4. producer

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @Component
    @Slf4j
    public class RabbitProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendMsgString(){
    String context = "ttang say: " + new Date();
    log.info(context);
    rabbitTemplate.convertAndSend("ttang", context);
    }

    public void sendMsgInt(int i){
    log.info("{}, {}", Thread.currentThread().getStackTrace()[1].getMethodName(), i);
    rabbitTemplate.convertAndSend("ttang", i);
    }
    }

  5. consumer

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    /**
    *
    * 接收消息
    *
    */
    @Component
    @RabbitListener(queues = "ttang")
    @Slf4j
    public class RabbitConsumer {

    @RabbitHandler
    public void receiveMsgString(String tt){
    log.info("收到ttang消息, {}", tt);
    }

    /**
    * Caused by: org.springframework.amqp.AmqpException: Ambiguous methods for payload type: class java.lang.String:
    * msg and msg2
    * 1. 不能有两个payload同时匹配, 会根据消息类型自动匹配
    * @param tt
    */
    @RabbitHandler
    public void receiveMsgInt(Integer tt){
    log.info("收到ttang消息2, {}", tt);
    }
    }

  6. test

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class RabbitConsumerTest {

    @Autowired
    private RabbitProducer producer;

    @Test
    public void msg() {
    // final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
    // for (int i = 0; i < 10; i++) {
    // fixedThreadPool.execute(() -> {
    // producer.sendMsgString();
    // });
    // }

    for (int i = 0; i < 10; i++) {
    producer.sendMsgInt(i);
    producer.sendMsgString();
    }
    }
    }

topicexchange 模式匹配订阅

依赖、地址同上

  1. queue,exchange配置, 配置路由规则

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    /**
    * 需要三个bean实例 queue, exchange, bindexchange
    *
    * queue1比queue2只有一个字母之差,模拟匹配
    */
    @Configuration
    public class TopicExchangeConfig {

    /**
    * 定制主题
    * @return
    */
    @Bean
    public TopicExchange topicExchange(){
    return new TopicExchange("topicExchange");
    }

    @Bean
    public Queue queueMessage(){
    return new Queue("topic.message");
    }

    /**
    * 精确匹配topic.message
    * @param queueMessage
    * @param topicExchange
    * @return
    */
    @Bean
    Binding bindingMessage(Queue queueMessage, TopicExchange topicExchange){
    return BindingBuilder.bind(queueMessage).to(topicExchange).with("topic.message");
    }

    @Bean
    public Queue queueMessages(){
    return new Queue("topic.messages");
    }

    /**
    * 匹配多个
    * *表示一个词.
    * #表示零个或多个词.
    *
    * 这个queue能接收多个消息
    * @param queueMessages
    * @param topicExchange
    * @return
    */
    @Bean
    Binding bindingMessages(Queue queueMessages, TopicExchange topicExchange){
    return BindingBuilder.bind(queueMessages).to(topicExchange).with("topic.#");
    }
    }

  2. 生产者

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    @Component
    @Slf4j
    public class TopicExchangeProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
    * 同时匹配 topic.message和 topic.# 所以会发到这两个queue里
    * @param msg
    */
    public void sendMessage(String msg){
    final StackTraceElement element = Thread.currentThread().getStackTrace()[1];
    log.info("{}, {}", element.getMethodName(), msg);
    rabbitTemplate.convertAndSend("topicExchange", "topic.message"
    , String.join(",", Arrays.asList(element.getClassName(), element.getMethodName(), msg)));
    }

    /**
    * 只能匹配到topic.#, 多了个s, 所以只会匹配发送到 queuemessages
    * BindingBuilder.bind(queueMessages).to(topicExchange).with("topic.#");
    * 相应的接收也只会是topic.messages
    * @param msg
    */
    public void sendMessages(String msg){
    final StackTraceElement element = Thread.currentThread().getStackTrace()[1];
    log.info("{}, {}", element.getMethodName(), msg);
    rabbitTemplate.convertAndSend("topicExchange", "topic.messages"
    , String.join(",", Arrays.asList(element.getClassName(), element.getMethodName(), msg)));
    }
    }

  3. 消费者

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    /**
    * 监听topic.message
    */
    @Slf4j
    @Component
    @RabbitListener(queues = "topic.message")
    public class TopicConsumerMessage {

    @RabbitHandler
    public void receiveMsgString(String msg){
    final StackTraceElement element = Thread.currentThread().getStackTrace()[1];
    log.info("{}, {}", element.getMethodName(), msg);
    }
    }

    /**
    * 监听topic.message
    */
    @Slf4j
    @Component
    @RabbitListener(queues = "topic.messages")
    public class TopicConsumerMessages {

    @RabbitHandler
    public void receiveMsgString(String msg){
    final StackTraceElement element = Thread.currentThread().getStackTrace()[1];
    log.info("{}, {}", element.getMethodName(), msg);
    }
    }

  4. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class TopicExchangeProducerTest {

    @Autowired
    private TopicExchangeProducer topicExchangeProducer;

    /**
    * 2019-08-11 12:54:46.482 INFO 18374 --- [ main] c.l.d.s.t.p.TopicExchangeProducer :
    * sendMessage, 我爱你 糖糖
    * <p>
    * <p>
    * 2019-08-11 12:54:46.502 INFO 18374 --- [ntContainer#2-1] c.l.d.s.t.c.TopicConsumerMessages :
    * receiveMsgString, com.lx.demo.springbootrabbitmq.tpcexchange.producer.TopicExchangeProducer,sendMessage,我爱你 糖糖
    * 2019-08-11 12:54:46.503 INFO 18374 --- [ntContainer#1-1] c.l.d.s.t.consumer.TopicConsumerMessage :
    * receiveMsgString, com.lx.demo.springbootrabbitmq.tpcexchange.producer.TopicExchangeProducer,sendMessage,我爱你 糖糖
    * 这里producer发送用的routing_key topic.message匹配topic.message和topic.#, 所以可以干到两个queue里, 相应的消费两个queue的都能接收到
    */
    @Test
    public void sendMessage() {
    topicExchangeProducer.sendMessage("我爱你 糖糖");
    }

    /**
    * 2019-08-11 12:57:00.110 INFO 18687 --- [ main] c.l.d.s.t.p.TopicExchangeProducer :
    * sendMessages, i love you, ttang
    * <p>
    * <p>
    * 2019-08-11 12:57:00.128 INFO 18687 --- [ Thread-2] o.s.a.r.l.SimpleMessageListenerContainer : Waiting
    * for workers to finish.
    * 2019-08-11 12:57:00.128 INFO 18687 --- [ntContainer#2-1] c.l.d.s.t.c.TopicConsumerMessages :
    * receiveMsgString, com.lx.demo.springbootrabbitmq.tpcexchange.producer.TopicExchangeProducer,sendMessages,i
    * love you, ttang
    * messages的消息发送者用的routing_key只能匹配topic.#, 所以只能到topic.messages这个queue
    */
    @Test
    public void sendMessages() {
    topicExchangeProducer.sendMessages("i love you, ttang");
    }
    }

fanoutexchange 发布订阅

依赖、地址同上

  1. queue配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    /**
    * 定义多个queue, 一个Fanoutexchange, 配置绑定binding
    * 这样发送到交换机上的消息都会传递到所有绑定queue
    *
    * 这个最像传统的主题订阅模式
    */
    @Configuration
    public class FanoutExchangeConfig {

    /**
    * 创建交换机
    * @return
    */
    @Bean
    FanoutExchange fanoutExchange(){
    return new FanoutExchange("fanoutExchange");
    }

    /**
    * 创建queue
    * @return
    */
    @Bean
    Queue fanoutQueue1(){
    return new Queue("fanout.1");
    }

    /**
    * 这里不在需要指定binding_key, 就算配了也么得用
    * @param fanoutQueue1
    * @param fanoutExchange
    * @return
    */
    @Bean
    Binding binding1(Queue fanoutQueue1, FanoutExchange fanoutExchange){
    return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
    }

    @Bean
    Queue fanoutQueue2(){
    return new Queue("fanout.2");
    }

    @Bean
    Binding binding2(Queue fanoutQueue2, FanoutExchange fanoutExchange){
    return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
    }

    @Bean
    Queue fanoutQueue3(){
    return new Queue("fanout.3");
    }

    /**
    * Description:
    *
    * Parameter 0 of method binding1 in com.lx.demo.springbootrabbitmq.fanoutexchange.config.FanoutExchangeConfig
    * required a single bean, but 6 were found:
    * - queue: defined by method 'queue' in class path resource
    * [com/lx/demo/springbootrabbitmq/direxchange/config/RabbitConfig.class]
    * - fanoutQueue1: defined by method 'fanoutQueue1' in class path resource
    * [com/lx/demo/springbootrabbitmq/fanoutexchange/config/FanoutExchangeConfig.class]
    * - fanoutQueue2: defined by method 'fanoutQueue2' in class path resource
    * [com/lx/demo/springbootrabbitmq/fanoutexchange/config/FanoutExchangeConfig.class]
    * - fanoutQueue3: defined by method 'fanoutQueue3' in class path resource
    * [com/lx/demo/springbootrabbitmq/fanoutexchange/config/FanoutExchangeConfig.class]
    * - queueMessage: defined by method 'queueMessage' in class path resource
    * [com/lx/demo/springbootrabbitmq/tpcexchange/config/TopicExchangeConfig.class]
    * - queueMessages: defined by method 'queueMessages' in class path resource
    * [com/lx/demo/springbootrabbitmq/tpcexchange/config/TopicExchangeConfig.class]
    *
    * @param fanoutQueue3
    * @param fanoutExchange
    * @return
    */
    @Bean
    Binding binding3(Queue fanoutQueue3, FanoutExchange fanoutExchange){
    return BindingBuilder.bind(fanoutQueue3).to(fanoutExchange);
    }

    }

  2. 生产者

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Component
    @Slf4j
    public class FanoutExchangeProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
    * fanout的方式不再需要routing-key
    * @param msg
    */
    public void sendMsg(String msg){
    log.info("{}, {}", Thread.currentThread().getStackTrace()[1].getMethodName(), msg);
    // 这里一定要注意函数重载,只有三个参数时,第一个才是exchange
    rabbitTemplate.convertAndSend("fanoutExchange","", msg);
    }
    }

    注意, 发送时是三个参数

  3. 消费者

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Slf4j
    @Component
    @RabbitListener(queues = "fanout.1")
    public class FanoutConsumer1 {

    @RabbitHandler
    public void receiveMessageString(String msg){
    log.info("{}, {}", Thread.currentThread().getStackTrace()[1].getMethodName(), msg);
    }
    }

  4. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class FanoutExchangeProducerTest {

    @Autowired
    private FanoutExchangeProducer fanoutExchangeProducer;

    /**
    * 2019-08-11 13:48:16.402 INFO 26183 --- [ main] c.l.d.s.f.p.FanoutExchangeProducer : sendMsg,
    * 大渣吼,我是范二特
    *
    *
    * 2019-08-11 13:48:16.425 INFO 26183 --- [ntContainer#2-1] c.l.d.s.f.consumer.FanoutConsumer2 :
    * receiveMessageString, 大渣吼,我是范二特
    * 2019-08-11 13:48:16.425 INFO 26183 --- [ntContainer#1-1] c.l.d.s.f.consumer.FanoutConsumer1 :
    * receiveMessageString, 大渣吼,我是范二特
    * 2019-08-11 13:48:16.425 INFO 26183 --- [ntContainer#3-1] c.l.d.s.f.consumer.FanoutConsumer3 :
    * receiveMessageString, 大渣吼,我是范二特
    *
    * 发送一条消息,上述三个消费者都收到了消息
    */
    @Test
    public void sendMsg() {
    fanoutExchangeProducer.sendMsg("大渣吼,我是范二特");
    }
    }

完整代码

https://github.com/microzhao/demo/tree/master/springboot/springboot-rabbitmq

mybatis多数据源

构建主从数据库

  1. 主库写入
  2. 从库读取

springboot多数据源配置

  1. 修改application.yaml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 配置主从数据源
    spring:
    datasource:
    master:
    jdbcUrl: jdbc:mysql://localhost:3306/mybatismaster?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
    username: root
    password: root
    slaver:
    jdbcUrl: jdbc:mysql://localhost:3306/mybatisslaver?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
    username: root
    password: root
  2. 修改configuration, 分别指定不同的mapper

    • master
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    package com.lx.demo.config;

    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;

    import javax.sql.DataSource;

    /**
    * 主域配置
    * 包括datasource session等, 都搞一套自己的
    */
    @Configuration
    @MapperScan(basePackages = "com.lx.demo.mapper.master", sqlSessionTemplateRef = "masterSqlSessionTemplate")
    public class DataSourceConfigMaster {

    /**
    * 创建主datasource, 这里多个数据源时必须指定一个为primary
    * @return
    */
    @ConfigurationProperties("spring.datasource.master")
    @Bean(name = "masterDataSource")
    @Primary
    public DataSource dataSource(){
    return DataSourceBuilder.create().build();
    }

    /**
    *
    * @param dataSource
    * @return
    * @throws Exception
    */
    @Bean(name = "masterSqlSessionFactory")
    @Primary
    public SqlSessionFactory sqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception {
    final SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    sqlSessionFactoryBean.setDataSource(dataSource);
    //如果使用xml的方式, 需要设置mybatis配置文件路径
    // sqlSessionFactoryBean.setConfigLocation("");
    return sqlSessionFactoryBean.getObject();
    }

    /**
    * 主域 事务管理器
    * @param dataSource
    * @return
    */
    @Bean(name = "masterDataSourceTransactionManager")
    @Primary
    public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("masterDataSource") DataSource dataSource){
    return new DataSourceTransactionManager(dataSource);
    }

    /**
    * 主 sqlsessiontemplet
    * @param sqlSessionFactory
    * @return
    */
    @Bean(name = "masterSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
    return new SqlSessionTemplate(sqlSessionFactory);
    }
    }

    • slaver
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    package com.lx.demo.config;

    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;

    import javax.sql.DataSource;

    /**
    * 从域配置
    * 包括datasource session等, 都搞一套自己的
    */
    @Configuration
    @MapperScan(basePackages = "com.lx.demo.mapper.slaver", sqlSessionTemplateRef = "slaverSqlSessionTemplate")
    public class DataSourceConfigSlaver {

    /**
    * 创建从datasource, 这里多个数据源时必须指定一个为primary
    * @return
    */
    @ConfigurationProperties("spring.datasource.slaver")
    @Bean(name = "slaverDataSource")
    public DataSource dataSource(){
    return DataSourceBuilder.create().build();
    }

    /**
    *
    * @param dataSource
    * @return
    * @throws Exception
    */
    @Bean(name = "slaverSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("slaverDataSource") DataSource dataSource) throws Exception {
    final SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    sqlSessionFactoryBean.setDataSource(dataSource);
    //如果使用xml的方式, 需要设置mybatis配置文件路径
    // sqlSessionFactoryBean.setConfigLocation("");
    return sqlSessionFactoryBean.getObject();
    }

    /**
    * 从域 事务管理器
    * @param dataSource
    * @return
    */
    @Bean(name = "slaverDataSourceTransactionManager")
    public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("slaverDataSource") DataSource dataSource){
    return new DataSourceTransactionManager(dataSource);
    }

    /**
    * 从 sqlsessiontemplet
    * @param sqlSessionFactory
    * @return
    */
    @Bean(name = "slaverSqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("slaverSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
    return new SqlSessionTemplate(sqlSessionFactory);
    }
    }

  3. 分别测试写入读取

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    public class UserController {

    /**
    * 同时注入主从库, 代码控制多数据源使用
    * 该方式只是多来源,其实没有动态切换
    */
    @Autowired
    private UserMapperMaster userMapperMaster;

    @Autowired
    private UserMapperSlaver userMapperSlaver;

    /**
    * 获取数据走从域
    * @param id
    * @return
    */
    @GetMapping("/user/{id}")
    public User selectOne(@PathVariable Long id){
    final User user = userMapperSlaver.getOne(id);
    return user;
    }

    @GetMapping("/users")
    public List<User> users(){
    return userMapperSlaver.getAll();
    }

    /**
    * 写入数据走主域
    */
    @PostMapping("/users")
    public void save(@RequestBody User user){
    userMapperMaster.insert(user);
    }
    }

通过注解切换主从数据源(个数固定)

与上述方式类似,只不过现在依赖一个bean, 然后通过注解方式切换数据源

  1. 主从数据源初始化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    /**
    * 配置多数据源
    */
    @Configuration
    @MapperScan(basePackages = "com.lx.demo.mapper.dynamic", sqlSessionTemplateRef = "dynamicSqlSessionTemplate")
    public class DataSourceConfigDynamic {

    /**
    * 创建主datasource, 这里多个数据源时必须指定一个为primary
    * @return
    */
    @ConfigurationProperties("spring.datasource.master")
    @Bean
    @Primary
    public DataSource dataSource1(){
    return DataSourceBuilder.create().build();
    }

    /**
    * 创建从datasource, 这里多个数据源时必须指定一个为primary
    * @return
    */
    @ConfigurationProperties("spring.datasource.slaver")
    @Bean
    public DataSource dataSource2(){
    return DataSourceBuilder.create().build();
    }

    /**
    * 动态数据源: 通过AOP在不同数据源之间动态切换
    * @return
    */
    @Bean(name = "dynamicDataSource")
    public DataSource dataSource() {
    DynamicDataSource dynamicDataSource = new DynamicDataSource();
    // 默认数据源
    dynamicDataSource.setDefaultTargetDataSource(dataSource1());

    // 配置多数据源
    Map<Object, Object> dsMap = new HashMap(5);
    dsMap.put("master", dataSource1());
    dsMap.put("slaver", dataSource2());
    dynamicDataSource.setTargetDataSources(dsMap);

    return dynamicDataSource;
    }

    /**
    *
    * @param dataSource
    * @return
    * @throws Exception
    */
    @Bean(name = "dynamicSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception {
    final SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    sqlSessionFactoryBean.setDataSource(dataSource);
    //如果使用xml的方式, 需要设置mybatis配置文件路径
    // sqlSessionFactoryBean.setConfigLocation("");
    return sqlSessionFactoryBean.getObject();
    }

    /**
    * 主域 事务管理器
    * @param dataSource
    * @return
    */
    @Bean(name = "dynamicDataSourceTransactionManager")
    public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("dynamicDataSource") DataSource dataSource){
    return new DataSourceTransactionManager(dataSource);
    }

    /**
    * 主 sqlsessiontemplet
    * @param sqlSessionFactory
    * @return
    */
    @Bean(name = "dynamicSqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("dynamicSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
    return new SqlSessionTemplate(sqlSessionFactory);
    }
    }

    • 注意,
      这里不要使用注入bean的方式初始化动态数据源,否则会产生循环依赖,直接用方法datasource1()这种即可
  2. 主从数据源管理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    /**
    * 主从数据源切换, 保存到threadLocal动态切换
    */
    @Slf4j
    public class DynamicDataSource extends AbstractRoutingDataSource {

    /**
    * 默认数据源
    */
    public static final String DEFAULT_DS = "master";

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    /**
    * 设置数据源
    * @param dbType
    */
    public static void setDB(String dbType) {
    log.debug("切换到{}数据源", dbType);
    contextHolder.set(dbType);
    }

    /**
    *
    * 获取数据源名
    * @return
    */
    public static String getDB() {
    return (contextHolder.get());
    }

    /**
    *
    * 清除数据源名
    */
    public static void clearDB() {
    contextHolder.remove();
    }

    @Override
    protected Object determineCurrentLookupKey() {
    log.debug("数据源为{}", DynamicDataSource.getDB());

    return DynamicDataSource.getDB();
    }

    }

  3. 利用反射执行方法时候动态切换数据源

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    /**
    * https://blog.csdn.net/neosmith/article/details/61202084
    */
    @Aspect
    @Component
    public class DynamicDataSourceAspect {

    @Before("@annotation(com.lx.demo.annotation.DS)")
    public void beforeSwitchDS(JoinPoint point) {

    //获得当前访问的class
    Class<?> className = point.getTarget().getClass();

    //获得访问的方法名
    String methodName = point.getSignature().getName();
    //得到方法的参数的类型
    Class[] argClass = ((MethodSignature) point.getSignature()).getParameterTypes();
    String dataSource = DynamicDataSource.DEFAULT_DS;
    try {
    // 得到访问的方法对象
    Method method = className.getMethod(methodName, argClass);

    // 判断是否存在@DS注解
    if (method.isAnnotationPresent(DS.class)) {
    DS annotation = method.getAnnotation(DS.class);
    // 取出注解中的数据源名
    dataSource = annotation.value();
    }
    } catch (Exception e) {
    e.printStackTrace();
    }

    // 切换数据源
    DynamicDataSource.setDB(dataSource);
    }

    /**
    * Caused by: java.lang.IllegalArgumentException: error Type referred to is not an annotation type: DS
    * @param point
    */
    @After("@annotation(com.lx.demo.annotation.DS)")
    public void afterSwitchDS(JoinPoint point) {
    DynamicDataSource.clearDB();
    }
    }

  4. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /**
    * 增加动态主从数据源注解, 配置后自动切换数据源
    * @param user
    */
    @DS("slaver")
    @PostMapping("/users-dy")
    public void saveByDynamic(@RequestBody User user){
    userMapperDynamic.insert(user);
    }

    @DS("slaver")
    @GetMapping("/users-dy")
    public List<User> usersByDynamic(){
    return userMapperDynamic.getAll();
    }


动态数据源(可以任意添加, 暂未实现)

问题列表

  1. 使用mybatisplus实现多数据源目前有问题,会报错
    org.apache.ibatis.binding.BindingException: Invalid bound statement
    (not found): com.yk.yearmeet.modular.service.UserService.list
  2. aspect @annotation(类的全限定名), 否则报错
    https://blog.csdn.net/yangshangwei/article/details/77619875 Caused
    by: java.lang.IllegalArgumentException: error Type referred to is
    not an annotation type: DS 这种方式才可以,
    @Before("@annotation(com.lx.demo.annotation.DS)")

代码路径

快捷键

自动代码

  • 常用的有fori/sout/psvm+Tab即可生成循环、System.out、main方法等boilerplate样板代码
  • 例如要输入for(User user : users)只需输入user.for+Tab
  • 再比如,要输入Date birthday =
    user.getBirthday();只需输入user.getBirthday().var+Tab即可。代码标签输入完成后,按Tab,生成代码。
  • Ctrl+Alt+O 优化导入的类和包, 清理import
  • Alt+Insert 生成代码(如get,set方法,构造函数等) 或者右键(Generate)
  • fori/sout/psvm + Tab
  • Ctrl+Alt+T 生成try catch 或者 Alt+enter
  • CTRL+ALT+T 把选中的代码放在 TRY{} IF{} ELSE{} 里
  • Ctrl + O 重写方法
  • Ctrl + I 实现方法
  • Ctr+shift+U 大小写转化
  • ALT+回车 导入包,自动修正
  • ALT+/ 代码提示
  • CTRL+J 自动代码
  • Ctrl+Shift+J,整合两行为一行
  • CTRL+空格 代码提示
  • CTRL+SHIFT+SPACE 自动补全代码
  • CTRL+ALT+L 格式化代码
  • CTRL+ALT+I 自动缩进
  • CTRL+E 最近更改的代码
  • CTRL+ALT+SPACE 类名或接口名提示
  • CTRL+P 方法参数提示
  • CTRL+Q,可以看到当前方法的声明
  • Shift+F6 重构重命名 (包、类、方法、变量、甚至注释等)
  • Ctrl+Alt+V 提取变量
  • 提取当前选择为变量(extract variable):CTRL+ALT+V
  • 提取当前选择为属性(extract field):CTRL+ALT+F
  • 提取当前选择为常量(extract constant):CTRL+ALT+C
  • 提取当前选择为方法(extract method):CTRL+ALT+M
  • 提取当前选择为方法参数(extract parameter):CTRL+ALT+P
  • 重构类、方法(change signarture):CTRL+F6
  • 提取代码块至if、try等结构中(surround with):CTRL+ALT+T
  • 创建模块文件等(new):CTRL+ALT+N
  • 创建测试用例(test):CTRL+SHIFT+T
  • 重构菜单(refactor for this):CTRL+T

查询快捷键

  • Ctrl+Shift+Backspace可以跳转到上次编辑的地
  • CTRL+ALT+ left/right 前后导航编辑过的地方
  • ALT+7 靠左窗口显示当前文件的结构
  • Ctrl+F12 浮动显示当前文件的结构, 查找当前类中的方法
  • ALT+F7 找到你的函数或者变量或者类的所有引用到的地方
  • CTRL+ALT+F7 找到你的函数或者变量或者类的所有引用到的地方
  • Ctrl+Shift+Alt+N 查找类中的方法或变量
  • 双击SHIFT 在项目的所有目录查找文件
  • Ctrl+N 查找类
  • Ctrl+Shift+N 查找文件
  • CTRL+G 定位行
  • CTRL+F 在当前窗口查找文本
  • CTRL+SHIFT+F 在指定窗口查找文本
  • CTRL+R 在 当前窗口替换文本
  • CTRL+SHIFT+R 在指定窗口替换文本
  • ALT+SHIFT+C 查找修改的文件
  • CTRL+E 最近打开的文件
  • F3 向下查找关键字出现位置
  • SHIFT+F3 向上一个关键字出现位置
  • 选中文本,按Alt+F3 ,高亮相同文本,F3逐个往下查找相同文本
  • F4 查找变量来源
    • //CTRL+SHIFT+O 弹出显示查找内容
    • Ctrl+W 选中代码,连续按会有其他效果, vim shift %
  • F2 或Shift+F2 高亮错误或警告快速定位
  • Ctrl+Up/Down 光标跳转到第一行或最后一行下
    • Ctrl+B 快速打开光标处的类或方法
  • CTRL+ALT+B 找所有的子类
  • CTRL+SHIFT+B 找变量的类
    • Ctrl+Shift+上下键 上下移动代码
  • Ctrl+X 删除行
  • Ctrl+D 复制行
  • Ctrl+/ 或 Ctrl+Shift+/ 注释(// 或者/*…*/ )
    • Ctrl+H 显示类结构图
  • Ctrl+Q 显示注释文档
    • Alt+F1 查找代码所在位置
  • Alt+1 快速打开或隐藏工程面板
    • Alt+ left/right 切换代码视图
  • ALT+ ↑/↓ 在方法间快速移动定位
  • CTRL+ALT+ left/right 前后导航编辑过的地方
  • Ctrl+Shift+Backspace可以跳转到上次编辑的地
  • Alt+6 查找TODO

其他快捷键

  • SHIFT+ENTER 另起一行
  • CTRL+Z 倒退(撤销)
  • CTRL+SHIFT+Z 向前(取消撤销)
  • CTRL+ALT+F12 资源管理器打开文件夹
  • ALT+F1 查找文件所在目录位置
  • SHIFT+ALT+INSERT 竖编辑模式
  • CTRL+F4 关闭当前窗口
  • Ctrl+Alt+V,可以引入变量。例如:new String(); 自动导入变量定义
  • Ctrl+~,快速切换方案(界面外观、代码风格、快捷键映射等菜单),
    可以切换主题

svn快捷键

  • ctrl+k 提交代码到SVN
  • ctrl+t 更新代码

调试快捷键

  • 其实常用的 就是F8 F7 F9 最值得一提的 就是Drop Frame
    可以让运行过的代码从头再来
  • alt+F8 debug时选中查看值
  • Alt+Shift+F9,选择 Debug
  • Alt+Shift+F10,选择 Run
  • Ctrl+Shift+F9,编译
  • Ctrl+Shift+F8,查看断点
    • F7,步入
  • Shift+F7,智能步入
  • Alt+Shift+F7,强制步入
  • F8,步过
  • Shift+F8,步出
  • Alt+Shift+F8,强制步过
    • Alt+F9,运行至光标处
  • Ctrl+Alt+F9,强制运行至光标处
  • F9,恢复程序
  • Alt+F10,定位到断点

重构

  • Ctrl+Alt+Shift+T,弹出重构菜单
  • Shift+F6,重命名
  • F6,移动
  • F5,复制
  • Alt+Delete,安全删除
  • Ctrl+Alt+N,内联

十大Intellij IDEA快捷键

Intellij
IDEA中有很多快捷键让人爱不释手,stackoverflow上也有一些有趣的讨论。每个人都有自己的最爱,想排出个理想的榜单还真是困难。以前也整理过Intellij的快捷键,这次就按照我日常开发时的使用频率,简单分类列一下我最喜欢的十大快捷神键吧。

  1. 智能提示:
    Intellij首当其冲的当然就是Intelligence智能!基本的代码提示用Ctrl+Space,还有更智能地按类型信息提示Ctrl+Shift+Space,但因为Intellij总是随着我们敲击而自动提示,所以很多时候都不会手动敲这两个快捷键(除非提示框消失了)。用F2/
    Shift+F2移动到有错误的代码,Alt+Enter快速修复(即Eclipse中的Quick
    Fix功能)。当智能提示为我们自动补全方法名时,我们通常要自己补上行尾的反括号和分号,当括号嵌套很多层时会很麻烦,这时我们只需敲Ctrl+Shift+Enter就能自动补全末尾的字符。而且不只是括号,例如敲完if/for时也可以自动补上{}花括号。最后要说一点,Intellij能够智能感知Spring、Hibernate等主流框架的配置文件和类,以静制动,在看似”静态”的外表下,智能地扫描理解你的项目是如何构造和配置的。

  2. 重构:
    Intellij重构是另一完爆Eclipse的功能,其智能程度令人瞠目结舌,比如提取变量时自动检查到所有匹配同时提取成一个变量等。尤其看过《重构改善既有代码设计》之后,有了Intellij的配合简直是令人大呼过瘾!也正是强大的智能和重构功能,使Intellij下的TDD开发非常顺畅。切入正题,先说一个无敌的重构功能大汇总快捷键Ctrl+Shift+Alt+T,叫做Refactor
    This。按法有点复杂,但也符合Intellij的风格,很多快捷键都要双手完成,而不像Eclipse不少最有用的快捷键可以潇洒地单手完成(不知道算不算Eclipse的一大优点),但各位用过Emacs的话就会觉得也没什么了(非Emacs黑)。此外,还有些最常用的重构技巧,因为太常用了,若每次都在Refactor
    This菜单里选的话效率有些低。比如Shift+F6直接就是改名,Ctrl+Alt+V则是提取变量。

  3. 代码生成:
    这一点类似Eclipse,虽不是独到之处,但因为日常使用频率极高,所以还是罗列在榜单前面。常用的有fori/sout/psvm+Tab即可生成循环、System.out、main方法等boilerplate样板代码,用Ctrl+J可以查看所有模板。后面”辅助”一节中将会讲到Alt+Insert,在编辑窗口中点击可以生成构造函数、toString、getter/setter、重写父类方法等。这两个技巧实在太常用了,几乎每天都要生成一堆main、System.out和getter/setter。另外,Intellij
    IDEA 13中加入了后缀自动补全功能(Postfix
    Completion),比模板生成更加灵活和强大。例如要输入for(User user :
    users)只需输入user.for+Tab。再比如,要输入Date birthday =
    user.getBirthday();只需输入user.getBirthday().var+Tab即可。

  4. 编辑:
    编辑中不得不说的一大神键就是能够自动按语法选中代码的Ctrl+W以及反向的Ctrl+Shift+W了。此外,Ctrl+Left/Right移动光标到前/后单词,Ctrl+[/]移动到前/后代码块,这些类Vim风格的光标移动也是一大亮点。以上Ctrl+Left/Right/[]加上Shift的话就能选中跳跃范围内的代码。Alt+Forward/Backward移动到前/后方法。还有些非常普通的像Ctrl+Y删除行、Ctrl+D复制行、Ctrl+</>折叠代码就不多说了。关于光标移动再多扩展一点,除了Intellij本身已提供的功能外,我们还可以安装ideaVim或者emacsIDEAs享受到Vim的快速移动和Emacs的AceJump功能(超爽!)。另外,Intellij的书签功能也是不错的,用Ctrl+Shift+Num定义110书签(再次按这组快捷键则是删除书签),然后通过Ctrl+Num跳转。这避免了多次使用前/下一编辑位置Ctrl+Left/Right来回跳转的麻烦,而且此快捷键默认与Windows热键冲突(默认多了Alt,与Windows改变显示器显示方向冲突,一不小心显示器就变成倒着显式的了,冏啊)。

  5. 查找打开:
    类似Eclipse,Intellij的Ctrl+N/Ctrl+Shift+N可以打开类或资源,但Intellij更加智能一些,我们输入的任何字符都将看作模糊匹配,省却了Eclipse中还有输入*的麻烦。最新版本的IDEA还加入了Search
    Everywhere功能,只需按Shift+Shift即可在一个弹出框中搜索任何东西,包括类、资源、配置项、方法等等。类的继承关系则可用Ctrl+H打开类层次窗口,在继承层次上跳转则用Ctrl+B/Ctrl+Alt+B分别对应父类或父方法定义和子类或子方法实现,查看当前类的所有方法用Ctrl+F12。要找类或方法的使用也很简单,Alt+F7。要查找文本的出现位置就用Ctrl+F/Ctrl+Shift+F在当前窗口或全工程中查找,再配合F3/Shift+F3前后移动到下一匹配处。Intellij更加智能的又一佐证是在任意菜单或显示窗口,都可以直接输入你要找的单词,Intellij就会自动为你过滤。

  6. 其他辅助:
    以上这些神键配上一些辅助快捷键,即可让你的双手90%以上的时间摆脱鼠标,专注于键盘仿佛在进行钢琴表演。这些不起眼却是至关重要的最后一块拼图有:

    • 命令:Ctrl+Shift+A可以查找所有Intellij的命令,并且每个命令后面还有其快捷键。所以它不仅是一大神键,也是查找学习快捷键的工具。
    • 新建:Alt+Insert可以新建类、方法等任何东西。
    • 格式化代码:格式化import列表Ctrl+Alt+O,格式化代码Ctrl+Alt+L。
    • 切换窗口:Alt+Num,常用的有1项目结构,3搜索结果,4/5运行调试。Ctrl+Tab切换标签页,Ctrl+E/Ctrl+Shift+E打开最近打开过的或编辑过的文件。
    • 单元测试:Ctrl+Shift+T创建单元测试用例。
    • 运行:Alt+Shift+F10运行程序,Shift+F9启动调试,Ctrl+F2停止。
    • 调试:F7/F8/F9分别对应Step into,Step over,Continue。

    此外还有些我自定义的,例如水平分屏Ctrl+|等,和一些神奇的小功能Ctrl+Shift+V粘贴很早以前拷贝过的,Alt+Shift+Insert进入到列模式进行按列选中。

    • Top #10切来切去:Ctrl+Tab
    • Top #9选你所想:Ctrl+W
    • Top #8代码生成:Template/Postfix +Tab
    • Top #7发号施令:Ctrl+Shift+A
    • Top #6无处藏身:Shift+Shift
    • Top #5自动完成:Ctrl+Shift+Enter
    • Top #4创造万物:Alt+Insert

    太难割舍,前三名并列吧!

    • Top #1智能补全:Ctrl+Shift+Space
    • Top #1自我修复:Alt+Enter
    • Top #1重构一切:Ctrl+Shift+Alt+T

全选复选框

  1. shift全部选中
  2. 空格勾选

一些实用的设置

  • live templete: idea中可以自定义一些自动生成方式, 很强大,
    类似sout生成, 目前将用户配置user.xml备份上传

  • 隐藏页签 setting–>editor–>general–>placement/none

  • 无法输入中文, fcitx, 修改idea安装目录下的执行命令idea.sh,
    在最前面加入与.xinitc一样的一些fcitx的环境变量

    • vim /usr/bin/idea.sh

    • 开头加入

      #!/bin/sh
      export XMODIFIERS="@im=fcitx"
      export GTK_IM_MODULE="fcitx"
      export QT_IM_MODULE="fcitx"
      if [ -z "$IDEA_JDK" ] ; then
              IDEA_JDK="/usr/lib/jvm/java-8-openjdk"
      fi
      exec env IDEA_JDK=$IDEA_JDK /usr/share/intellijidea-ce/bin/idea.sh $@
      
    • 使用的jdk版本可以加入环境变量 export IDEAJDK="$JAVAHOME"

    • 注意,确认下idea.sh中引号是否正确,不然还是不能输入中文

  • idea重新安装后无法import project, 改用社区版本+ remote断点的方式

    • 首先在weblogic域中打开debugflag(默认端口8453)(setdomainenv),
      或者将内容复制到startweblogic.sh启动参数中

      1
      2
      JAVA_DEBUG="-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=4000,server=y,suspend=n"
      export JAVA_DEBUG
    • 启动weblogic服务后,idea中新建remote,
      修改访问的地址以及端口即可, 注意,一定要指定modu

  • idea vim插件 :actionlist 显示所有的快捷键,(好牛逼..)

  • ctrl-shift v: idea的历史剪贴板

  • 神奇的Inject language

    • Inject language or reference。
    • alt-enter
    • enter
    • json file
    • alter-enter – > json file fragment
    • 编辑完成后ctrl-f4退出
  • 擦屁股快捷键ctrl+shift+enter

  • ctrl-w alt-j批量修改

  • 代码在项目中的定位: alt-f1 –> 选择project –> enter, 如果还想回去
    f4

  • idea配置同步, setting>repository

    1. github建立一个新的项目
    2. setting–> resp中url使用这个项目
    3. 这就是个github项目随便玩.
  • 隐藏页签, 在页签右键,none

  • 社区版没有 import setting选项,所以安装主题ui就直接搜plugin,
    然后找对应主题名即可

修改host, 防止idea检测注册信息

127.0.0.1 localhost.localdomain localhost arch ::1 localhost.localdomain
localhost arch ### idea 0.0.0.0 account.jetbrains.com

插件推荐

  • ideavim

  • lombok 可选, 定义bean的时候不用在写getset

  • Alibaba Java Coding Guidelines plugin 阿里规范

  • findbugs 避免低级bug

  • maven helper据说很吊, 暂时没用, 排查maven依赖的

  • generateallsetter 自定调用一个bean的set方法

    1
    2
    3
    User user = new User();
    alt-enter
    选择自动生成
  • key promoter 这个插件是告诉你个傻x, 输入几次了还及不住快捷键

arch linux (linux 命令很强大, 命令才是王道啊~~~)

  1. f.lux 根据经纬度调整屏幕亮度

  2. 网易云音乐 (这段时间跪了, 打开白板 )

  3. sublime text 偶尔当下记事本

  4. 为知笔记 笔记软件, 因为跨平台我就支持了

  5. input

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #export XIM=fcitx
    #export XIM_PROGRAM=fcitx
    #export GTK_IM_MODULE=fcitx
    #export QT_IM_MODULE=fcitx
    #export XMODIFIERS="@im=fcitx"

    #firefox keyi dazile
    export LC_ALL=zh_CN.UTF-8
    export GTK_IM_MODULE=fcitx
    export QT_IM_MODULE=fcitx
    export XMODIFIERS=“@im=fcitx”
    exec openbox-session
    #exec xfce4-session
    #exec gnome-session
  6. 文件比较: meld vimdiff diff等

  7. 文本编辑器 emacs vim

  8. webtorrenter-desktop 播放bt文件

  9. 图形界面连接网络 sudo pacman -S network-manager-applet (需要启动
    systemctl start NetworkManager)

  10. rescue time 有兴趣可以看看, 这个是记录你一天在干嘛的软件, 后台运行
    nohut rescuetime &(会在当前文件夹下生成nohup.out文件)

  11. 跨平台文件传输 feige
    url:http://www.feige360.com/ipmsg/download.html

  12. 锁屏 yaourt -S xlockmore

  13. create_ap github下的一个项目, 共享热点必备

    1
    配置启动: nohup sudo create_ap wlp2s0 enp0s20u2u4 archer 1234567890 > /tmp/create_ap.log & tail -f /tmp/create_ap.log
  14. 数据传输工具, 类似飞球, yaourt -s iptux,
    但是最新的0.75版本有问题, 不能扫描局域网用户,
    目前使用0.6.4版本进行源码编译安装

  15. 使用zsh + oh my zsh

  16. 开发工具使用idea, community

    • 插件:
      • ideavim: vi模式, 用过都说好
      • Key promoter: 快捷键菜鸡必备,比如我
      • Markdown support
  17. sqldeveloper安装

    • oracle 限制, 需要登录下载,
      所以先到官网下载sqldeveloper18.nojar.zip
    • pacman -S oracle-sqldeveloper
    • 安装过程中将刚刚下载的zip包放到其他pass文件同级的目录, 继续即可
  18. postman curl 模拟请求

  19. processon/graphviz 流程图

    • c-c c-c编译执行dot文件
  20. dropbox

  21. ag搜索 the_silver_searcher

  22. xml处理工具 xmlstarlet, jq处理json, shyaml处理yaml

  23. 命令行剪贴板工具xclip

  24. pandoc 文档转换工具

  25. cairo-dock dock工具,样式挺好看,不过习惯了launcher运行, 不喜欢点,
    不使用

  26. 同步工具

    • Dropbox 这玩意儿有qiang, 并且你的文件需要服务器中转
    • syncthing, 这个东东是通过p2p发送,可以设备互传,好东西
  27. 截图工具 scrot

    • scrot 全屏
    • scrot -s 截取
    • scrot -e 'mv $f ~/Pictures/scrot_screenshots' 截图后执行命令
  28. 命令行下模糊搜索工具 fzf

    • 搭配其它工具或者自己组合命令都很6,可以作为插件加入到vim, ranger,
      zsh中
    • 通过搜索可以更方便的打开文件,不用一一展开
  29. 简化版命令手册 tldr, 我这里使用的是tealdeer,arch默认的使用不了,
    可以优雅的查看常用命令的基本使用方式

  30. 远程连接windows桌面

    • rdesktop 192.168.2.144 -p lt@180606 -u lt1 -g workarea
    • rdesktop 192.168.2.144 -p password -u username -r
      disk:share=/tmp
      可以将当前系统下/tmp目录作为共享磁盘给远程服务器,可以实现文件copy

问题处理

  1. 网易云音乐白板 : rm `locate netease |grep cache` 删掉缓存即可

制作U盘启动盘

  • 下载archlinux镜像
  • 下载powerison
  • 将镜像刻录到U盘中

设置bios

  • 如果已经安装了win8+系统,
    开机重启然后按f1,进入设置界面,加载启动项中将usb放到最前
  • 保存后,插入启动盘重启,按f12, 选择启动项,选择archlinux

分区

  • 工具:fdisk , 使用m指令查看支持的操作
  • 重建分区表干掉所有分区 fdisk /dev/sda, g(是gpt分区表)
    w(这个指令后所做的配置就会生效)
  • 创建分区 n{ /dev/sda1(efi), dev/sda2(), /dev/nvmxxx(/home)},
    我的分区是nvmxx(固态在前, 所以分区方案是/dev/nvm1(efi),
    dev/nvmxx2()…)
  • 格式化分区
    • mkfs.vfat -F32 /dev/sda1
    • mkfs.ext4 /dev/sda2 , 其他分区都使用ext4
  • 分区挂载
    • mount /dev/sda2 /mnt
    • mount /dev/sda1 /mnt/boot/efi
    • mount /dev/sda3 /mnt/home

网络连接

  • 有网线的情况下直接跳过第二步
  • 连接wifi
    • 首先查看网卡 ip link命令列出网卡id
    • systemctl stop dhcpxxx.service 关闭现有网络
    • wifi-menu -o wlp3s0,选择可连接网络连接
  • 配置服务镜像
    • 如果是在中国, 就把mirrorlist中的china相关镜像提前,
      我这里只把163的镜像放最前面

安装系统

  • 安装基本包

    • pacman -sy 刷新系统更新文件
    • 安装基础系统及后续工具, base-devel也可以装好系统后再安装
      #pacstrap -i /mnt base base-devel
  • 配置fstab

    • # /dev/nvme0n1p2
      UUID=7bdc64d4-20ed-4073-bcef-dacefcee8e9a       /               ext4            rw,relatime     0 1
      
      # /dev/nvme0n1p1
      UUID=FAB8-E796          /boot/efi       vfat            rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro       0 2
      
      # /dev/nvme0n1p3
      UUID=48256cfb-3694-4102-85fb-33d9142f554c       /home           ext4            rw,relatime     0 2
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21

      - 挂载机械硬盘/dev/sda1时需要注意,直接在fstab中配置方式导致开机无法启动,后查看官方文档,改为按需挂载,
      这种情况下正常启动,如果有外部对改磁盘进行了引用也会自动挂载

      UUID=6e3a49e9-131b-4003-b251-cc26eae107ca /mnt/d ext4
      noauto,x-systemd.automount 0 0

      - 安装引导工具(这里一定要弄对,否则进不去系统, 严格顺序执行)
      后续操作全部在安装的系统里进行
      - 下面这个必须执行, 生成grub.cfg配置文件, 默认安装系统会自带一个

      ``` {.example}
      arch-chroot /mnt
      GRUB启动, UEFI的系统,要装grub-efi-x86_64和efibootmgr
      #pacman -S grub-efi-x86_64, efibootmgr
      把GRUB装到EFI分区里,这样就多一条GRUB启动项了。
      #grub-install --efi-directory=/boot/efi --bootloader-id=arch-grub --recheck
      生成grub配置文件(否则启动一致会报grub的错误)
      pacman -S os-prober
      #grub-install /dev/sda(根目录下, 如果出现grub缺少文件时候再执行)
      grub-mkconfig -o /boot/grub/grub.cfg
  • 为了下次可以连无线最好安装下 pacman -S iw wpasupplicant dialog

  • exit, 取消必要的挂载后重启, 系统已经安装完成

一些必要的优化及软件安装

重启后进入自己安装好的系统

时区,编码

  • 生成localtime的软链就算设置时区了。 #ln -s
    /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
  • 设置系统时间是当地时间,Linux默认是UTC时间,Windows默认是当地时间,改成一致。
    #hwclock –localtime

编码

  • 打开locale.gen文件,把enUS.UTF-8, zhCN.UTF-8,
    zhCN.GBK前面的#去掉。
  • 运行locale-gen命令,重建编码表。

host设置

  • 设置电脑名,随你喜欢。

    • #echo arch-zhao > /etc/hostname
  • 设置hosts文件 vim /etc/hosts

    1
    2
    3
    127.0.0.1 localhost
    ::1 localhost
    127.0.1.1 arch-zhao.localdomain arch-zhao

图形界面

  • 安装xorg pacman -S xorg

  • 触摸板驱动 pacman -S xf86-input-synaptics

  • 根据自己显卡类型安装对应的驱动

    • 确认型号 lspci | grep VGA

    • 官方提供驱动

      1
      2
      3
      4
      通用———————————-xf86-video-vesa 
      intel———————————-xf86-video-intel
      Geforce7+————————–xf86-video-nouveau
      Geforce6/7————————-xf86-video-304xx
  • 安装字体(图形界面需要) pacman -S ttf-dejavu wqy-microhei

  • 安装yaourt vim /etc/pacman.conf [archlinuxcn] SigLevel=Never
    Server = https://mirrors.ustc.edu.cn/archlinuxcn/$arch

  • binutils, yaourt 需要进行二进制编译(安装了base-devel后不需要)

  • 安装桌面环境 xde(好看), xfce(轻量), openbox(定制化)

    • kde桌面安装 pacman -S plasma
    • 文件管理器 pacman -S dolphin
    • 命令行 pacman -S konsole
    • kde工具套件 pacman -S kde-applications(这个我没安装)
  • 启动网络管理 systemctl enable NetworkManager , 安装前端管理工具
    network-manage-applet, 或者pacman -S plasma-nm

  • 安装slim (启动管理器, 用习惯了,类似还有很多), 执行systemctl enable
    slim(允许开机自启)

  • .xinintrc配置 cp etc/X11/xinit/xinitrc ~.xinitrc vim ~/.xinitrc
    加入exec startkde 启动kde

  • 安装openssh sudo pacman -S openssh (非必须)

  • 安装chromium

  • reflector 镜像刷新工具, 可以扫描最快的镜像提前

    1. 备份原镜像 cp /etc/pacman.d/mirrorlist
      /etc/pacman.d/mirrorlist.bak
    2. 查找最快200个源并写入到镜像文件 reflector –verbose -l 200 -p
      http –sort rate –save /etc/pacman.d/mirrorlist
  • 后续软件按个人需要安装

环境准备

  • 华为云 centos系统
  • 本地已经正常使用, 需要部署到服务器并且需要用docker启动
  • web容器使用weblogic10.3.6
  • 本人的原始环境为archlinux

操作步骤

本地环境打包

  • 注意: 采用本地环境为了省事, 本地环境包含整个的weblogic环境, 及jdk,
    如果自己心情好完全可以再搭建一套
1
2
tar -zcvf weblogic.tar.gz ~/Oracle #这个目录是weblogic的默认安装及建域目录, 相应的war包也在该目录下
tar -zcvf jdk.tar.gz ~/applications/jdk1.7 #jdk

上传到云服务器

  • 上传打包好的文件

    • weblogic

      1
      2
      scp weblogic.tar.gz root@11x.xxx.xxx.xxx:/root  
      根据提示输入密码稍等上传完成
    • jdk

      1
      2
      scp jdk.tar.gz root@11x.xxx.xxx.xxx:/root  
      根据提示输入密码稍等上传完成
  • 解压, 找一个自己喜欢的目录,建议跟本地保持一致

    • 在服务建立与本地一致的目录

      1
      mkdir ~/applications
    • 解压文件

      1
      2
      tar -zxvf /root/weblogic.tar.gz -C ~
      tar -zxvf /root/jdk.tar.gz -C ~/applications
  • 在云服务器上配置启动web服务,
    并通过弹性公网访问或者服务器本地确认服务启动正常

    • 进入domain目录启动服务验证

      1
      nohup ./startWeblogic.sh & tail -f nohup.out

使用docker容器启动

制作docker镜像

  • Dockerfile文件

    • touch ~/Dockerfile

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      #Dockerfile  
      # 基于centos构建本容器
      FROM centos
      # 跟本地映射的端口, 这里相当与访问本地7003会自动转发到容器中7003
      EXPOSE 7003
      #设置环境变量,所有操作都是非交互式的
      ENV LANG en_US.UTF-8
      ENV LC_ALL en_US.UTF-8
      ENV DEBIAN_FRONTEND noninteractive
      #可以安装软件
      #RUN yum install xx
      # 需要打到docker中的文件全部copy到docker对应的目录中, 本地目录是相对当前目录,不能写绝对路径, 后面这个路径最好加/
      COPY . ~/
      COPY cmd.sh /cmd.sh
      # 容器启动后直接执行给定脚本
      CMD sh /cmd.sh
      #End
    • 制作镜像

      • 进入目录 ~ 在目录 ~中目前存在

        1
        2
        3
        4
        drwxr-xr-x 3 root root 4096 Sep 30 10:49 applications
        -rwxr-xr-x 1 root root 128 Sep 30 11:17 cmd.sh
        -rw-r--r-- 1 root root 305 Sep 30 17:07 Dockerfile
        drwxr-xr-x 3 root root 4096 Jul 14 18:39 Oracle
      • 执行命令 docker build -t payimage .

        • 最后的点表示dockerfile在当前目录
      • 查看存在镜像 docker images

        1
        2
        3
        REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
        payimage latest d7b3db0e1d59 15 hours ago 2.22 GB
        centos latest c5507be714a7 7 weeks ago 199.7 MB
  • docker commit命令通过运行中容器制作镜像

    1
    docker commit pay7003 payimages:v1.0

启动容器

  • cmd.sh

    1
    2
    3
    #!/bin/bash
    domainname=$1 # 这里如果没有其他情况可以写死
    nohup sh ~/Oracle/Middleware/user_projects/domains/$domainname/startWebLogic.sh > /7003.log & tail -f /7003.log
  • 通过上一步镜像启动

    1
    2
    3
    4
    5
    6
    7
    8
    9
    docker  run -itd --net=host --name pay7003 payimage sh /cmd.sh
    命令解释:
    -i:
    -t:
    -d: 保持,退出后不关闭docker
    --name: docker容器的名称
    payimage: 镜像名称
    --net=host: 这个必须有,否则启动报错
    sh /cmd.sh: 这个是容器启动会执行的命令, 以后docker start 也会执行该文件
  • 可以省略第一步操作直接制作容器启动, 不使用docfile直接制作镜像

    1
    2
    3
    4
    docker run itd -v weblogic:weblogic idk:jdk --net=host -p7003:7003 --name=pay7003 centos
    上面的weblogic前后分别表示本地的目录和远程的目录
    -v 可以达到dockfile中copy的效果
    -p 表示端口映射
  • 容器管理

    1
    2
    3
    docker start pay7003
    docker stop pay7003
    docker rm pay7003 #删除容器, 先stop再rm

连接容器,检查服务

  • 查看现有容器

    • docker ps -a

      1
      2
      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
      dc2eeca7873e payimage "sh /cmd.sh" 15 hours ago Exited (137) 15 hours ago pay7003
  • 登录容器

    1
    2
    docker exec -it pay7003 bash #这里pay7003是容器name, 也可以使用容器id
    通过该命令可以连接到容器pay7003的bash中, 跟正常操作cenos系统一样, 完成后exit即可

容器管理

大杀器片甲不留, 自己玩可以用

1
docker kill $(docker ps -q) ; docker rm $(docker ps -a -q) ; docker rmi $(docker images -q -a) 

删除镜像

1
docker rmi payimage

问题处理

archlinux中启动docker实例报错

  • systemctl start docker.service报错,直接使用systemctl enable
    docker.service重启机器正常

docker镜像持久化到本地(待测试)

  • 有的项目太大了,而且是公司内部使用不合适到公网
  • docker save java -o ./java.tar
  • copy到其他伙伴机器后可以使用: docker load -i java.tar,
    加载到对方容器中
  • 参考: https://segmentfault.com/a/1190000006843830

docker到底能干个啥?

  • 在团队内部构建本地的仓库,标准化所有的开发环境,使得团队的新人可以快速上手
  • 在生产环境部署Docker,这其实是PaaS的虚拟化和自动化的一种方式,利用LXC和Docker能够更便捷地实施PaaS
  • 尝试用Docker做分布式集群模拟和测试,成本会更加低廉,更加容易维护
  • 参考:
    https://www.csdn.net/article/2014-06-19/2820312-Docker-lxc-paas-virtualization

nodejs项目初始化

  1. 创建目录 mkdir nodejs & cd nodejs

  2. npm init (根据提示,或者一路回车即可)

  3. 创建server.js文件,并写入以下内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 内置组件  
    var http=require("http");

    http.createServer(function(request, response){
    // 发送 HTTP 头部
    // HTTP 状态值: 200 : OK
    // 内容类型: text/plain
    response.writeHead(200, {"Content-Type":"text/plain"});

    //响应数据
    response.end("hello nodejs");
    }).listen(8888);
    //服务启动成功后输出日志
    console.log('Server running at http://127.0.0.1:8888/');
  4. node server.js 启动成功

  5. 浏览器访问 127.0.0.1:8888

npm使用(root)

搜索

  • npm search

更新

  • npm install -g npm

  • npm update -g npm

安装卸载模块

  • 当前目录
    npm install
    npm uninstall

  • 全局
    npm install -g
    npm uninstall -g

查看模块安装信息

  • 一个
    npm list -g

  • 所有
    npm list

Package.json属性说明

1
2
3
4
5
6
7
8
9
10
name - 包名。
version - 包的版本号。
description - 包的描述。
homepage - 包的官网 url 。
author - 包的作者姓名。
contributors - 包的其他贡献者姓名。
dependencies - 依赖包列表。如果依赖包没有安装,npm 会自动将依赖包安装在 node_module 目录下。
repository - 包代码存放的地方的类型,可以是 git 或 svn,git 可在 Github 上。
main - main 字段指定了程序的主入口文件,require('moduleName') 就会加载这个文件。这个字段的默认值是模块根目录下面的 index.js。
keywords - 关键字

whatis npm

  1. npm就是js下的maven, 支持包依赖, 执行等
  2. package.json == pom.xml

var 和 const

初始化buffer

  • 类似于初始化一个list
  • Buffer.alloc(5)

nodejs对标的是其他的后端语言类似java

require的执行流程

  1. 如果 X 是内置模块
  2. 返回内置模块
  3. 停止执行
  4. 如果 X 以 ‘/‘ 开头
    1. 设置 Y 为文件根路径
  5. 如果 X 以 ‘./‘ 或 ‘/‘ or ‘../‘ 开头
    1. LOAD_AS_FILE(Y + X)
    2. LOAD_AS_DIRECTORY(Y + X)
  6. LOAD_NODE_MODULES(X, dirname(Y))
  7. 抛出异常 “not found”

extend

Sub 仅仅继承了Base 在原型中定义的函数,而构造函数内部创造的 base 属 性和 sayHello 函数都没有被 Sub 继承。

总结

如果有一定变成基础,nodejs还是很easy的, 例子6一下就可以, 入门容易,用好就需要code code code!

  1. everything 搜索神器, 强烈推荐
  2. faststone capture 红绿小工具,工具小功能强
  3. clcl 复制粘贴神器
  4. f.lux linux和windows都用,自动根据经纬度调整屏幕亮度
  5. launchy 运行软件(可以自己将软件的快捷方式起别名放入一个目录,该软件引用,很爽)
  6. 自己编写的一些 bat小工具 自动化
  7. 远程工具 anydesk teamview
  8. zeal 文档阅读器
  9. itellij idea java开发工具
    插件推荐: vim plantuml(这个玩意儿依赖于一个小软件(graphviz), 需要单独装)、 jprofiler(需要配套对应的软件, 用来查看系统耗时,作为调节性能的依据)
  10. 软媒魔方 偶尔用用 更新软件了什么的, 现在随便找个软件管理什么的,可以省下满世间找软件的尴尬
  11. unlocker 文件诡异的锁住了,用这个解锁,随便搞
  12. ccleaner 电脑清理的,不知道为啥一直用着
  13. beyond compare 文件比较软件
  14. rescue time 有兴趣可以看看, 这个是记录你一天在干嘛的软件
  15. gvim 文本编辑器 我一般只用这个和notepad++
  16. scoop命令行下的包管理器,软件有点少但是社区还是很给力的, 建议添加extral包
  1. dism++ 垃圾清理, 备份还原,等。
  2. spacesniffer 无需安装,分析磁盘,清理文件
  3. 独立版本qq软件管理

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

0%