spring Boot重点岗要(二)启动方式-注解-静态与动态资源-事务-全局异常处理等

  • 启动
  • springboot应用热加载/热启动,可行的方案。
    • 模板的热启动
    • 类的热启动
  • 注解
    • @Controller和@RestController注解区别
    • @SpringBootApplication
      • @EnableAutoConfiguration
      • @ComponentScan
    • @EnableConfigurationProperties与@ConfigurationProperties
      • 1.@ConfigurationProperties与@Configuration或者 @Component一起使用.
      • 2.@ConfigurationProperties与@EnableConfigurationProperties一起使用
  • 模块
  • 打包,部署命令
  • 静态资料和动态页面
    • 静态页面
    • 动态页面
    • 动态和静态区别
  • 全局异常处理
  • 事务

启动

1.IDE工具内以application方式启动
这个最简单,执行main函数启动应用.

2.java命令行方式
使用mvn install生成可执行jar,然后执行java -jar运行程序.

java -jar xxx.jar [--server.port=8090等参数]

以java命令行方式启动,并可携带参数(可选参数),通过使用–server.port属性来设置xxx.jar应用的端口为8888。在命令行运行时,连续的两个减号–就是对application.properties中的属性值进行赋值的标识,命令行属性总是优先于其他属性源。所以java -jar xxx.jar –server.port=8888命令,等价于我们在application.properties中添加属性–server.port=8888
官文提供的属性

3.使用Maven插件运行
Spring Boot Maven插件包含一个run目标,可用来快速编译和运行应用程序,并且跟在IDE运行一样支持热加载。

mvn spring-boot:run

springboot应用热加载/热启动,可行的方案。

有2个相似的概念。
1.热部署:就是容器状态在运行的情况下重新部署整个项目.在这种情况下一般整个内存会清空,重新加载。自动重启整个项目
2.热加载:就是容器状态在运行的情况下重新加载改变编译后的类.在这种情况下内存不会清空,sessin不会丢失,但容易造成内存溢出,或者找不到方法。自动加载被编译过的类。
springboot能做到热加载/热启动。

模板的热启动

在spring boot里,模板引擎的页面默认是开启缓存的,如果修改了页面的内容,想通过刷新是得不到修改后的页面的,我们可以通过修改application.properties配置文件来达到模板热部署的功能,properties配置文件修改如下:

Thymeleaf的配置:
spring.thymeleaf.cache=false
FreeMarker的配置:
spring.freemarker.cache=false
Groovy的配置:
spring.groovy.template.cache=false
Velocity的配置:
spring.velocity.cache=false

类的热启动

1.引入spring-boot-devtools

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-devtoolsartifactId>
    <optional>trueoptional>
dependency>

注意引入的是spring-boot-devtools模块而不是spring-boot-starter-devtools,差一个starter
如果用IDEA工具则不需要引入插件,如果使用eclipse则要引入下面插件

<plugin>  
     <groupId>org.springframework.bootgroupId>  
      <artifactId>spring-boot-maven-pluginartifactId>  
      <configuration>  
          <fork>truefork>  
      configuration>  
  plugin>

2.设置IDEA环境Setting->Build,Execution,Deployment->Compiler->Build project automatically
同时按住快捷键 Shift+command+Alt+/,选择Registry,找到compiler.automake.allow.when.app.running并勾选。
重启IDEA,第一次尝试可能不会成功。多试几次,你要相信,这么多人都成功了,你怎么会不成功呢。
spring-boot-devtools工作原理

3.关闭自动重启,application.properties添加属性

spring.devtools.restart.enabled=false

或main方法里设置

System.setProperty("spring.devtools.restart.enabled","false");

推荐第一种。

注解

@Controller和@RestController注解区别

1.使用@Controller 注解,在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面
若返回json等内容到页面,则需要加@ResponseBody注解。例如

@Controller
@RequestMapping("/bss")
public class CoupController {

    /**
     * 返回json对象
     * @return
     */
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    @ResponseBody
    public Object list() {
        return "result";
    }

    /**
     * 解析jsp,html页面
     * @param addrPk
     * @return
     */
    @RequestMapping(value = "/editView", method = RequestMethod.GET)
    public ModelAndView editView(@RequestParam(value = "addrPk", required = false) Long addrPk) {
        return new ModelAndView("bss/addr/edit");
    }
}

2.返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面。例如

@RestController
@RequestMapping("/bss")
public class HelloController {

    @RequestMapping("/hello1")
    public String index() {
        return "Hello World";
    }
}

@SpringBootApplication

Springboot 提供了@SpringBootApplication统一的注解来替代@SpringBootConfiguration, @EnableAutoConfiguration,@ComponentScan,简化程序的配置。

@EnableAutoConfiguration

这就是spring boot的核心功能,自动配置。就是根据当前引入的JAR包进行自动配置,比如:
引入了jackson的jar包,那么就会自动配置json转换,所以这里可以使用@ResponseBody
引入了spring boot的web模块,就会自动配置web.xml等与web项目相关的内容,所以这些配置都不需要我们自己配了

@ComponentScan

用注解配置实现自动扫描,默认会扫描当前包和所有子包,和xml配置自动扫描效果一样,所以当用SpringBootApplication替代ComponentScan注解时,它会如ComponentScan一样扫描当前包及其子包,故启动类的位置是有要求的。
当前也可以指定字扫描的包名。语法如下@ComponentScan(basePackages = "com.cn.config")
springboot启动自动扫描的3种方式:
方式一:此种情况下,针对比较特殊的情形,即项目中运用了SpringBoot,则可以利用@SpringBootApplication注解的方式启动自动扫描功能.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

方式二:通过XML配置方式,启动自动扫描功能.XML配置方式


<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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.tianmaying" />
beans>

标签将会开启Spring Beans的自动扫描,并可设置base-package属性,表示Spring将会扫描该目录以及子目录下所有被@Component标注修饰的类,对它们进行装配。

方式三:通过Java配置方式,启动自动扫描功能.

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "com.cn.config")
public class BlogSystemConfig {
    /**
     * 在这里实现java方式的配置,
     */
}

(1)@Configuration表示这个Java文件是一个配置文件,这类Java代码的作用在于配置,要和普通的Java代码区分开发,因此一般我们需要将其放在一个专门的包中,在代码例子中是com.cn.config。

(2)@ComponentScan表示开启Spring Beans扫描,类似于XML配置,这里也可以可以设置basePackages属性。
如果@ComponentScan注解没有显示去给其他的属性赋值的话,比如此处给basePackages赋值了,如果没有的话,@ComponentScan注解会扫描与配置类相同的包.

@EnableConfigurationProperties与@ConfigurationProperties

@EnableConfigurationProperties注解是用来开启对@ConfigurationProperties注解配置Bean的支持。
也就是@EnableConfigurationProperties注解告诉Spring Boot 使能支持@ConfigurationProperties
@ConfigurationProperties将配置文件映射到POJO类上,使用方式如下2种:

1.@ConfigurationProperties与@Configuration或者 @Component一起使用.

例如application.myl配置如下:
name:cy
则使用如下:

@Component//或@Configuration
@ConfigurationProperties
public class CC {
    private String name;

    @Value("${name}")
    private String nameC;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getNameC() {
        return nameC;
    }

    public void setNameC(String nameC) {
        this.nameC = nameC;
    }
}

2.@ConfigurationProperties与@EnableConfigurationProperties一起使用

@EnableConfigurationProperties指定了哪些类属于配置文件.
POJO配置文件(去掉@Component):

@ConfigurationProperties
public class CC {
    private String name;

    @Value("${name}")
    private String nameC;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getNameC() {
        return nameC;
    }

    public void setNameC(String nameC) {
        this.nameC = nameC;
    }
}

启动类如下:

@SpringBootApplication
@EnableConfigurationProperties(CC.class)
public class LeanmybatisApplication {

    public static void main(String[] args) {
        SpringApplication.run(LeanmybatisApplication.class, args);
    }
}

@EnableConfigurationProperties指定CC类配置文件.

模块

spring-boot-starter:起动器模块,核心模块,包括自动配置支持、日志和YAML,其它模块的依赖。
spring-boot-starter-xxx:代表一个spring boot模块
spring-boot-starter-web:代表web模块,在这个模块中含了许多jar包,引入web相关的jar,其中比较特殊的是嵌入式tomcat需要的jar包

打包,部署命令

打包

mvn install

部署运行。以命令行方式起动并指定端口

java -jar XXX.jar --server.port=8081

静态资料和动态页面

springboot是没有webapp或WebContent/WebRoot目录的,静态资料放在static目录下,动态放在templates目录下。一般将资源目录创建在resources目录下。resources/staticresources/templates目录为spring boot默认配置的静态资料和动态页面路径。最终目的是编译结果目录target/classes下有static和templates。如下图
spring Boot重点岗要(二)启动方式-注解-静态与动态资源-事务-全局异常处理等_第1张图片

静态页面

那么访问静态url会跳转到static目录下寻找静态页面
比如本地服务,端口8080。
1.static目录有个home.html.访问url:http://localhost:8080/home.html
2.如果要从后台跳转到静态home.html

@Controller
public class HtmlController {
    @GetMapping("/html")
    public String html() {
        return "/home.html";
    }

会自动从static目录下寻找home.html页面,注意跳转静态页面要带后缀。

动态页面

动态页面是访问到目录templates下的。
例如:

@Controller  
public class TemplatesController {    

    @GetMapping("/templates")  
    String test(HttpServletRequest request) {  
        //逻辑处理  
        request.setAttribute("key", "hello world");  
        return "/index";  
    }    
}  

return “/index”: 跳转到 templates/index.html动态页面,templates目录为spring boot默认配置的动态页面路径。

动态和静态区别

静态页面的return默认是跳转到/static/index.html,当在pom.xml中引入了thymeleaf组件,动态跳转会覆盖默认的静态跳转,默认就会跳转到/templates/index.html,
注意静态是return "/home.html";,动态是 return "/index"; ,动态没有html后缀。
在引入thymeleaf组件后还想使用静态跳转,则需要重定向return "redirect:/index.html"; 属于客户端跳转

引入thymeleaf组件pom.xml代码如下:

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-thymeleafartifactId>
dependency>

全局异常处理

springboot有个默认的异常处理映射/error,是动态页面,当处理中抛出异常之后,会从templates目录找/templates/error.html页面。
全局异常类GlobalExceptionHandler,使用切面编程,拦截请求,注意要与启动类同一目录或其子目录下。

@ControllerAdvice
public class GlobalExceptionHandler {
    public static final String DEFAULT_ERROR_VIEW = "error";
    //拦截Exception异常,返回页面
    @ExceptionHandler(value = Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        ModelAndView mav = new ModelAndView();
        mav.addObject("exception", e);
        mav.addObject("url", req.getRequestURL());
        mav.setViewName(DEFAULT_ERROR_VIEW);
        return mav;
    }

    //拦截MyException异常,返回json格式数据,@ExceptionHandler之后加入@ResponseBody,就能让处理函数return的内容  转换为JSON格式
    @ExceptionHandler(value = MyException.class)
    @ResponseBody
    public String defaultMyErrorHandler(HttpServletRequest req, MyException e) throws Exception {
        return e.toString();
    }
}

resources/templates/error.html页面如下:


<html>
<head lang="en">
    <meta charset="UTF-8" />
    <title>统一异常处理title>
head>
<body>
    <h1>Error Handler1h1>
    <div th:text="${url}">div>
    <div th:text="${exception.message}">div>
body>
html>

api请求

public static boolean isJson(ServletRequest request) {
        String isJson= ((HttpServletRequest) request).getHeader("isJson");
        return null != isJson&& isJson.equals("1");
    }

    @GetMapping("/testError")
    @ResponseBody
    public Object testError(HttpServletRequest request) throws Exception {
        if (isJson(request)) {
            // 如果是ajax请求
            throw new MyException("1000", "测试异常");
        }
        throw new Exception("测试异常");
    }

请求http://127.0.0.1:8080/bss/testError,如果头部有参数isJson且值为1则抛出MyException,否则抛Exception,异常抛出被拦截器GlobalExceptionHandler拦截到,根据@ExceptionHandler指定的异常处理类执行对应的处理函数,MyException异常以json格式返回错误,Exception以html页面形势返回。

只需在@ExceptionHandler之后加入@ResponseBody,就能让处理函数return的内容转换为JSON格式

事务

事务即保持数据一致性,和spring里概念一样.
springboot里只要引入对应的starter模块即可直接使用事务@Transactional.
注意点:
1.@Transactional注解来自org.springframework.transaction.annotation包,而不是javax.transaction

2.可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,作用于方法上时则覆盖类上的事务。

3.@Transactional默认是针对unchecked exception回滚。也就是默认对RuntimeException异常或是其子类进行事务回滚,checked异常即使用try…catch…捕获的异常不回滚.若想回滚,需要手动写代
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

4.设置回滚点:Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
回滚到savePoint:TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);

5.@Transactional属性

参 数 名 称 功 能 描 述
value 配置事务管理器,转为管理器是transactionManager
readOnly 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)
rollbackFor 该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
rollbackForClassName 该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:指定单一异常类名称@Transactional(rollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,”Exception”})
noRollbackFor 该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
noRollbackForClassName 该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(noRollbackForClassName={“RuntimeException”,”Exception”})
propagation 该属性用于设置事务的传播行为。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
isolation 该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
timeout 该属性用于设置事务的超时秒数,默认值为-1表示永不超时,其单位是秒

特别说如下2点
事务隔离级别isolation
我们可以看org.springframework.transaction.annotation.Isolation枚举类中定义了五个表示隔离级别的值:

public enum Isolation {
    DEFAULT(-1),
    READ_UNCOMMITTED(1),
    READ_COMMITTED(2),
    REPEATABLE_READ(4),
    SERIALIZABLE(8);
}

使用方法通过使用isolation属性设置:@Transactional(isolation = Isolation.DEFAULT)

事务传播行为propagation
我们可以看org.springframework.transaction.annotation.Propagation枚举类中定义了6个表示传播行为的枚举值:

public enum Propagation {
    REQUIRED(0),
    SUPPORTS(1),
    MANDATORY(2),
    REQUIRES_NEW(3),
    NOT_SUPPORTED(4),
    NEVER(5),
    NESTED(6);
}

使用方法:通过使用propagation属性设置:@Transactional(propagation = Propagation.REQUIRED)

6.并不需要main方法的类上添加@EnableTransactionManagement,一样可以使用@Transactional ,无须显示开启使用@EnableTransactionManagement注解

7.多事务管理器
引入jpa模块则框架会默认注入DataSourceTransactionManager实例

<dependency>
     <groupId>org.springframework.bootgroupId>
     <artifactId>spring-boot-starter-data-jpaartifactId>
 dependency>

引入jdbc模块则框架会默认注入JpaTransactionManager实例

<dependency>
     <groupId>org.springframework.bootgroupId>
     <artifactId>spring-boot-starter-jdbcartifactId>
 dependency>

2个事务管理器名称都叫transactionManager,当然这是一个项目只有一个事务管理器情况,当有多数据源,存在多个事务管理器时,则需要使用@Transactional的value属性@Transactional(value="txManager1")

public class TestApplication{
    @Resource(name="txManager1")
    private PlatformTransactionManager txManager1;

    // 创建事务管理器1
    @Bean(name = "txManager2")
    public PlatformTransactionManager txManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    // 创建事务管理器2
    @Bean(name = "txManager3")
    public PlatformTransactionManager txManager2(EntityManagerFactory factory) {
        return new JpaTransactionManager(factory);
    }

    // 实现接口 TransactionManagementConfigurer 方法,其返回值代表在拥有多个事务管理器的情况下默认使用的事务管理器
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return txManager2;
    }
}
public class TestServiceImpl {
    // 使用value具体指定使用哪个事务管理器
    @Transactional(value="txManager1")
    @Override
    public void send() {
        System.out.println(">>>>>>>>Dev Send()<<<<<<<<");
        send2();
    }

    // 在存在多个事务管理器的情况下,如果使用value具体指定
    // 则默认使用方法 annotationDrivenTransactionManager() 返回的事务管理器
    @Transactional
    public void send2() {
        System.out.println(">>>>>>>>Dev Send2()<<<<<<<<");
    }
}

你可能感兴趣的:(springboot)