0
点赞
收藏
分享

微信扫一扫

【檀越剑指大厂—Spring】Spring应用


一.注解使用

1.value 注解

如果配置文件中没有 demo.num 配置属性,启动时就会报错,spring 加载不到此属性值。

@value("${demo.num}")

如果配置文件中没有 demo.num 配置属性,取默认值 100。

@value("${demo.num:100}")

二.日志打印

SpringBoot 中 使用 [info] 日志级别打印 mybatis sql 语句
在 Spring Cloud 项目中,生产环境需要打印 mybatis 的 sql 语句日志,但是 mybatis 打印的 sql 的默认日志级别是 [debug],如果生产环境想看到 sql 语句,就必须开启[debug] 级别的日志打印,这样做 debug 日志量过大,显然不可行。

解决思路
Spring Boot 中通过 logback 打印 mybatis 的 sql 语句日志,并自定义日志输出实现将 sql 语句 [debug] 日志级别上升到 [info] 日志级别
解决方案

1.日志原理

常用的 mybatis 日志输出是由 org.apache.ibatis.logging.stdout.StdOutImpl 控制的
根据 StdOutImpl.java 可看出日志都是 System.out.println(s); 的控制台输出,配置及源码如下

#application.xml
mybatis:
  type-aliases-package: com.jiafupeng.mapper
  mapper-locations: classpath:mapper*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台输出日志

public class StdOutImpl implements Log {

  public StdOutImpl(String clazz) {

  }

  @Override
  public boolean isDebugEnabled() {
    return true;
  }

  @Override
  public boolean isTraceEnabled() {
    return true;
  }

  @Override
  public void error(String s, Throwable e) {
    System.err.println(s);
    e.printStackTrace(System.err);
  }

  @Override
  public void error(String s) {
    System.err.println(s);
  }

  @Override
  public void debug(String s) {
    System.out.println(s);
  }

  @Override
  public void trace(String s) {
    System.out.println(s);
  }

  @Override
  public void warn(String s) {
    System.out.println(s);
  }
}

2.自定义 log

要想改变 mybatis sql 语句输出内容级别,则只需自定义 Log 实现类,重写 mybatis sql 打印方式及级别。代码如下

#application.xml
mybatis:
  type-aliases-package: com.jiafupeng.mapper
  mapper-locations: classpath:mapper*.xml
  configuration:
 log-impl: com.jiafupeng.util.MySlf4jImpl # mybatis自定义日志输出实现类 并将[debug]日志输出成[info]日志

@Slf4j
public class MySlf4jImpl implements Log {
    public MySlf4jImpl(String clazz) {
    }

    @Override
    public boolean isDebugEnabled() {
        return log.isInfoEnabled();
    }

    @Override
    public void debug(String s) {
        log.info(s);
    }
}

3.配置 log 输出

指定 logback 的日志级别为 info,也可在 [info] 级别日志中查看 mybatis 的 sql 语句。

#logback.xml
<!-- 日志输出级别 -->
<root level="info">
 <appender-ref ref="FILE-INFO"/>
</root>

<!-- 如果想将mybatis-sql[info]日志单独输出到一个文件中,就加上如下配置 -->
<!-- <logger name="com.jiafupeng.util.MySlf4jImpl" level="info" additivity="false">-->
<!-- <appender-ref ref="FILE-SQL"/>-->
<!-- </logger>-->

4.设置不打印

生产环境如果不想打印 mybatis sql 则注释掉打印实现类即可,或者使用 NoLoggingImpl.java 作为实现类,具体看源码。

mybatis:
  type-aliases-package: com.jiafupeng.mapper
  mapper-locations: classpath:mapper*.xml
或

mybatis:
  type-aliases-package: com.jiafupeng.mapper
  mapper-locations: classpath:mapper*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl # 无日志(默认有debug日志)

三.xml 配置

1.管理类

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config/>
    <!--注入user类-->
    <bean id="user" class="com.kwan.spring5.User"></bean>
    <!--spring方式: set方法注入属性-->
    <bean id="book" class="com.kwan.spring5.Book">
        <!--使用property完成属性注入
            name:类里面属性名称
            value:向属性注入的值
        -->
        <property name="bname" value="Hello"></property>
        <property name="bauthor" value="World"></property>
    </bean>
    <!--(2)spring方式:有参数构造注入属性-->
    <bean id="orders" class="com.kwan.spring5.Orders">
        <constructor-arg name="oname" value="Hello"></constructor-arg>
        <constructor-arg name="address" value="China!"></constructor-arg>
    </bean>
</beans>

public class Spring_01_BookTest {
  @Test
  public void test1() {
    ApplicationContext ctx =
      new ClassPathXmlApplicationContext("spring1.xml");
    Book book = (Book) ctx.getBean("book");
    System.out.println(book);
  }
}

四.常见问题

1.事务问题

1.1.事务失效

插入数据

@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private TestDao dao;

    @Override
    //@Transactional
    public void insert() {
        this.save();
        //throw new RuntimeException();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void save() {
        dao.insert("test");
        dao.update();
        throw new RuntimeException("aaa");
    }

}

1.2.未插入数据

@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private TestDao dao;

    @Override
    @Transactional
    public void insert() {
        this.save();
        //throw new RuntimeException();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void save() {
        dao.insert("test");
        dao.update();
        throw new RuntimeException("aaa");
    }

}

1.3.未插入数据

save 方法的事务被 insert 方法的事务一起接管了

@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private TestDao dao;

    @Override
    @Transactional
    public void insert() {
        this.save();
        throw new RuntimeException();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void save() {
        dao.insert("test");
        dao.update();
        //throw new RuntimeException("aaa");
    }

}

2.@Nullable

@Nullable 注解可以使用在方法、属性、参数上,分别表示方法返回可以为空、属性值可以为空、参数值可以为空。

3.Alias标签

在bean标签里边有一个alias属性和name属性,可以指定bean的别名,但是有的场景下,在定义bean的时候就把他的别名都指定好是不适用的.
比如这个Bean在组件A中,想把他叫做componentA,但是在组件B中又想把他叫做componetB,所以还有一个单独的标签:< alias>专门解决上述场景的.

<bean id="myBean" class="com.itpluto.MyBean"></bean>
<alias name="myBean" alias="componetA">
<alias name="myBean" alias="componetB">

4.Import标签

import的使用场景主要是因为项目比较大,配置文件非常多的时候,会进行分模块,这个时候就可以用到import这个标签了.

  • 获取resource属性的值
    解析路径中的系统属性,比如:${user.dir}
  • 根据resource的值来判断是绝对路径还是相对路径
  • 如果是绝对路径直接加载解析文件即可
  • 如果是相对路径要先计算出绝对路径
  • 通知监听器,解析完成.

<import resource="customerContext.xml" />
<import resource="systemContext.xml" />

5.读取xml

1.ApplicationContext

ClassPathXmlApplicationContext ctx = 
				new ClassPathXmlApplicationContext("applicationContext.xml");
		User user = (User) ctx.getBean("user");

2.BeanFactory

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
		User user1 = (User) bf.getBean("user");

3.项目根路径

FileSystemXmlApplicationContext fct = 
				new FileSystemXmlApplicationContext("/src/main/resources/applicationContext.xml");
		User user2 = (User) fct.getBean("user");

4.系统根路径

String rootPath = System.getProperty("user.dir");
		BeanFactory bf1 = new XmlBeanFactory(
				new FileSystemResource(rootPath+"/src/main/resources/applicationContext.xml"));
		User user3 = (User) bf1.getBean("user");

5.监听器

<!-- web启动读取applicationContext.xml -->
	  <listener>
	  	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	  </listener>
	  <context-param>
	  	<param-name>contextConfigLocation</param-name>
	  	<param-value>classpath:applicationContext.xml</param-value>
	  </context-param>

6.环绕通知

@Around(value = "myPointCut()")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
{
  Object[] args = proceedingJoinPoint.getArgs();
  Object result=null;
  try {
    //前置通知@Before
    System.out.println("环绕前置通知");
    //目标方法执行
    result = proceedingJoinPoint.proceed(args);
    //环绕返回通知@AfterReturning
    System.out.println("环绕返回通知");
  } catch (Throwable throwable) {
    //环绕异常通知@AfterThrowing
    System.out.println("环绕异常通知");
    throw new RuntimeException(throwable);
  } finally {
    //最终通知@After
    System.out.println("环绕最终通知");
  }
  return result;
}

五.特殊工具

1.发邮件工具类

package com.deepexi.bfp.financial.service.domain.bill.service.impl;

import com.deepexi.bfp.financial.service.domain.bill.config.MailPropertiesConfig;
import com.deepexi.bfp.financial.service.domain.bill.service.IMailService;
import com.deepexi.bfp.financial.service.domain.bill.utils.SuperCsvUtil;
import com.deepexi.util.exception.ApplicationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.*;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Properties;

@Slf4j
@Service
public class MailServiceImpl implements IMailService {

    @Autowired
    private MailPropertiesConfig mailConfig;

    @Override
    public void send(String email, File file) {
        try {
            Properties props = new Properties();
            props.put("mail.smtp.host ", mailConfig.getHost());
            props.put("mail.smtp.auth", mailConfig.getAuth());
            Session session = Session.getInstance(props);
            Message message = new MimeMessage(session);
            InternetAddress from = new InternetAddress(mailConfig.getAddress());
            message.setFrom(from);
            InternetAddress to = new InternetAddress(email);
            message.setRecipient(Message.RecipientType.TO, to);
            message.setSubject(MimeUtility.encodeText("交易对帐平台"));
            message.setSentDate(new Date());
            MimeMultipart msgMultipart = new MimeMultipart("mixed");// 指定为混合关系
            message.setContent(msgMultipart);
            // 邮件内容
            MimeBodyPart htmlPart = new MimeBodyPart();
            htmlPart.setContent(
                    "<body>"
                            + "<div>"
                            + "交易对帐平台,对账差异信息,请查看附件" + "</div></body>",
                    "text/html;charset=UTF-8");
            //组装的顺序非常重要,一定要先组装文本域,再组装文件
            msgMultipart.addBodyPart(htmlPart);
            // 组装附件
            MimeBodyPart mimeBodyPart = new MimeBodyPart();
            FileDataSource file_datasource = new FileDataSource(file.getPath());
            DataHandler dh = new DataHandler(file_datasource);
            mimeBodyPart.setDataHandler(dh);
            // 附件区别内嵌内容的一个特点是有文件名,为防止中文乱码要编码
            mimeBodyPart.setFileName(MimeUtility.encodeText(dh.getName()));
            msgMultipart.addBodyPart(mimeBodyPart);
            message.saveChanges();
            Transport transport = session.getTransport("smtp");
            transport.connect(mailConfig.getHost(), mailConfig.getPort(), mailConfig.getUsername(), mailConfig.getPassword());
            transport.sendMessage(message, message.getAllRecipients());
            transport.close();
        } catch (MessagingException | UnsupportedEncodingException e) {
            throw new ApplicationException("发送邮件失败");
        }
        log.info("工单邮件发送完毕");
        SuperCsvUtil.deleteFile(file.getPath());
    }
}


举报

相关推荐

0 条评论