XxwGit 的个人博客

记录精彩的程序人生

目录
SpringBoot系列教程(二)Web篇(下)
/  

SpringBoot系列教程(二)Web篇(下)

Spring Boot属性配置文件详解

自定义属性与加载

我们在使用SpringBoot进行开发时,可以使用一下自定义的配置,在许多的情况下,我们都需要定义一些自己使用的属性,那么应该如何做呢?
接下来会逐步讲解如何在SpringBoot中使用自定义属性:

  1. 首先在application.properties文件中输入自定义属性
com.xxw.test.name=xuxinwei
com.xxw.test.location=beijing
  1. 在java文件中使用Value标签对application.properties文件中的属性进行调用
    @Component+@Value
@Component
@RestController
public class ConfigTest {
	@Value("${com.xxw.test.name}")
	private String name;
	@Value("${com.xxw.test.location}")
	private String location;
	
	@RequestMapping("/getConfig")
	public String getConfig() {
		return name+" is in "+location;
	}

参数间的引用

在application.properties中的各个参数之间也可以直接引用来使用,就像下面的设置:

com.xxw.test.name=xuxinwei
com.xxw.test.location=beijing
com.xxw.test.desc = ${com.xxw.test.name} say he is in ${com.xxw.test.location}

使用随机数

在一些情况下,有些参数我们需要希望它不是一个固定的值,比如密钥、服务端口等。Spring Boot的属性配置文件中可以通过${random}来产生int值、long值或者string字符串,来支持属性的随机值。

# 随机字符串
com.didispace.blog.value=${random.value}
# 随机int
com.didispace.blog.number=${random.int}
# 随机long
com.didispace.blog.bignumber=${random.long}
# 10以内的随机数
com.didispace.blog.test1=${random.int(10)}
# 10-20的随机数
com.didispace.blog.test2=${random.int[10,20]}

通过命令行设置属性值

相信使用过一段时间Spring Boot的用户,一定知道这条命令:java -jar xxx.jar --server.port=8888,通过使用–server.port属性来设置xxx.jar应用的端口为8888。

在命令行运行时,连续的两个减号--就是对application.properties中的属性值进行赋值的标识。所以,java -jar xxx.jar --server.port=8888命令,等价于我们在application.properties中添加属性server.port=8888,该设置在样例工程中可见,读者可通过删除该值或使用命令行来设置该值来验证。

通过命令行来修改属性值固然提供了不错的便利性,但是通过命令行就能更改应用运行的参数,那岂不是很不安全?是的,所以Spring Boot也贴心的提供了屏蔽命令行访问属性的设置,只需要这句设置就能屏蔽:SpringApplication.setAddCommandLineProperties(false)。

多环境配置

我们在开发Spring Boot应用时,通常同一套程序会被应用和安装到几个不同的环境,比如:开发、测试、生产等。其中每个环境的数据库地址、服务器端口等等配置都会不同,如果在为不同环境打包时都要频繁修改配置文件的话,那必将是个非常繁琐且容易发生错误的事。

对于多环境的配置,各种项目构建工具或是框架的基本思路是一致的,通过配置多份不同环境的配置文件,再通过打包命令指定需要打包的内容之后进行区分打包,Spring Boot也不例外,或者说更加简单。

在Spring Boot中多环境配置文件名需要满足application-{profile}.properties的格式,其中{profile}对应你的环境标识,比如:

  • application-dev.properties:开发环境
  • application-test.properties:测试环境
  • application-prod.properties:生产环境
    至于哪个具体的配置文件会被加载,需要在application.properties文件中通过spring.profiles.active属性来设置,其值对应{profile}值。

如:spring.profiles.active=test就会加载application-test.properties配置文件内容

下面,以不同环境配置不同的服务端口为例,进行样例实验。

  • 针对各环境新建不同的配置文件application-dev.properties、application-test.properties、application-prod.properties

  • 在这三个文件均都设置不同的server.port属性,如:dev环境设置为1111,test环境设置为2222,prod环境设置为3333

  • application.properties中设置spring.profiles.active=dev,就是说默认以dev环境设置

  • 测试不同配置的加载

    • 执行java -jar xxx.jar,可以观察到服务端口被设置为1111,也就是默认的开发环境(dev)
    • 执行java -jar xxx.jar --spring.profiles.active=test,可以观察到服务端口被设置为2222,也就是测试环境的配置(test)
    • 执行java -jar xxx.jar --spring.profiles.active=prod,可以观察到服务端口被设置为3333,也就是生产环境的配置(prod)
      按照上面的实验,可以如下总结多环境的配置思路:

application.properties中配置通用内容,并设置spring.profiles.active=dev,以开发环境为默认配置
application-{profile}.properties中配置各个环境不同的内容
通过命令行方式去激活不同环境的配置

Spring Boot构建RESTful API

首先,回顾并详细说明一下在快速入门中使用的@Controller、@RestController、@RequestMapping注解。如果您对Spring MVC不熟悉并且还没有尝试过快速入门案例,建议先看一下快速入门的内容。

  • @Controller:修饰class,用来创建处理http请求的对象
  • @RestController:Spring4之后加入的注解,原来在@Controller中返回json需要@ResponseBody来配合,如果直接用@RestController替代@Controller就不需要再配置@ResponseBody,默认返回json格式。
    @RequestMapping:配置url映射
    下面我们尝试使用Spring MVC来实现一组对User对象操作的RESTful API,配合注释详细说明在Spring MVC中如何映射HTTP请求、如何传参。

实体类

public class UserInfo {
	private Long id; 
    private String name; 
    private Integer age;
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	} 
}

功能类

@RestController
@RequestMapping(value = "/users")
public class UserController {
	static Map<Long, UserInfo> users = Collections.synchronizedMap(new HashMap<Long, UserInfo>());
	@RequestMapping(value="/", method=RequestMethod.GET) 
    public List<UserInfo> getUserList() { 
        // 处理"/users/"的GET请求,用来获取用户列表 
        // 还可以通过@RequestParam从页面中传递参数来进行查询条件或者翻页信息的传递 
        List<UserInfo> r = new ArrayList<UserInfo>(users.values()); 
        return r; 
    } 
 
    @RequestMapping(value="/", method=RequestMethod.POST) 
    public String postUser(@ModelAttribute UserInfo user) { 
        // 处理"/users/"的POST请求,用来创建User 
        // 除了@ModelAttribute绑定参数之外,还可以通过@RequestParam从页面中传递参数 
        users.put(user.getId(), user); 
        return "success"; 
    } 
 
    @RequestMapping(value="/{id}", method=RequestMethod.GET) 
    public UserInfo getUser(@PathVariable Long id) { 
        // 处理"/users/{id}"的GET请求,用来获取url中id值的User信息 
        // url中的id可通过@PathVariable绑定到函数的参数中 
        return users.get(id); 
    } 
 
    @RequestMapping(value="/{id}", method=RequestMethod.PUT) 
    public String putUser(@PathVariable Long id, @ModelAttribute UserInfo user) { 
        // 处理"/users/{id}"的PUT请求,用来更新User信息 
        UserInfo u = users.get(id); 
        u.setName(user.getName()); 
        u.setAge(user.getAge()); 
        users.put(id, u); 
        return "success"; 
    } 
 
    @RequestMapping(value="/{id}", method=RequestMethod.DELETE) 
    public String deleteUser(@PathVariable Long id) { 
        // 处理"/users/{id}"的DELETE请求,用来删除User 
        users.remove(id); 
        return "success"; 
    } 
}

Spring Boot开发Web应用

静态资源访问

在我们开发Web应用的时候,需要引用大量的js、css、图片等静态资源。

我们可以在src/main/resources/目录下创建static,在static下创建images文件夹用于存储图片资源,在该位置放置一个图片文件。启动程序后,尝试访问http://localhost:8080/images/1.jpg 。如能显示图片,配置成功。

渲染Web页面

在之前的示例中,我们都是通过@RestController来处理请求,所以返回的内容为json对象。那么如果需要渲染html页面的时候,要如何实现呢?

模板引擎

在动态HTML实现上Spring Boot依然可以完美胜任,并且提供了多种模板引擎的默认配置支持,所以在推荐的模板引擎下,我们可以很快的上手开发动态网站。

Spring Boot提供了默认配置的模板引擎主要有以下几种:

  • Thymeleaf
  • FreeMarker
  • Velocity
  • Groovy
  • Mustache
    Spring Boot建议使用这些模板引擎,避免使用JSP,若一定要使用JSP将无法实现Spring Boot的多种特性,具体可见后文:支持JSP的配置

当你使用上述模板引擎中的任何一个,它们默认的模板配置路径为:src/main/resources/templates。当然也可以修改这个路径,具体如何修改,可在后续各模板引擎的配置属性中查询并修改。

下面我介绍一下常用的模板引擎 Thymeleaf:
Thymeleaf是一个XML/XHTML/HTML5模板引擎,可用于Web与非Web环境中的应用开发。它是一个开源的Java库,基于Apache License 2.0许可,由Daniel Fernández创建,该作者还是Java加密库Jasypt的作者。

Thymeleaf提供了一个用于整合Spring MVC的可选模块,在应用开发中,你可以使用Thymeleaf来完全代替JSP或其他模板引擎,如Velocity、FreeMarker等。Thymeleaf的主要目标在于提供一种可被浏览器正确显示的、格式良好的模板创建方式,因此也可以用作静态建模。你可以使用它创建经过验证的XML与HTML模板。相对于编写逻辑或代码,开发者只需将标签属性添加到模板中即可。接下来,这些标签属性就会在DOM(文档对象模型)上执行预先制定好的逻辑。

示例模板:

  1. 添加依赖
    Gradle:
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

Maven:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  1. 创建功能类
@Controller
public class ThyController {
	@RequestMapping("/thy")
    public String index(ModelMap map) {
        // 加入一个属性,用来在模板中读取
        map.addAttribute("host", "blog.xxw.cn");
        // return模板文件的名称,对应src/main/resources/templates/index.html
        return "index";  
    }
}
  1. 创建前端页面
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8" />
    <title></title>
</head>
<body>
<h1 th:text="${host}">Hello World</h1>
</body>
</html>

Spring Boot中使用Swagger2构建强大的RESTful API文档

SpringBoot具有能够快速开发,便捷部署等强大的特性,许多用户都会选择用来构建RESTful API。我们之所以使用RESTful API,大多都是由于终端的原因,这些终端会共用许多的底层业务逻辑,因此我们会抽象出这样一层来同时服务于多个移动端或者Web前端。

RESTful API的重磅好伙伴Swagger2

它可以轻松的整合到Spring Boot中,并与Spring MVC程序配合组织出强大RESTful API文档。它既可以减少我们创建文档的工作量,同时说明内容又整合入实现代码中,让维护文档和修改代码整合为一体,可以让我们在修改代码逻辑的同时方便的修改文档说明。

RESTful API

什么是RESTful API REST,即Representational State Transfer的缩写。直接翻译的意思是"表现层状态转化"。它是一种互联网应用程序的API设计理念:URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。

开始使用Swagger2

  1. 添加Swagger2依赖
    Gradle:
implementation 'io.springfox:springfox-swagger2:2.2.2‘
implementation 'io.springfox:springfox-swagger-ui:2.2.2'

Maven:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.2.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.2.2</version>
</dependency>
  1. 创建Swagger2配置类
    在Application.java同级创建Swagger2的配置类Swagger2。
@Configuration
@EnableSwagger2
public class Swagger2 {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.didispace.web"))
                .paths(PathSelectors.any())
                .build();
    }
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Spring Boot中使用Swagger2构建RESTful APIs")
                .description("更多Spring Boot相关文章请关注:http://blog.didispace.com/")
                .termsOfServiceUrl("http://blog.didispace.com/")
                .contact("程序猿DD")
                .version("1.0")
                .build();
    }
}
  1. 添加文档内容
@RestController
@RequestMapping(value = "/users")
public class UserController {
	static Map<Long, UserInfo> users = Collections.synchronizedMap(new HashMap<Long, UserInfo>());
	@ApiOperation(value="获取用户列表", notes="")
	@RequestMapping(value="/", method=RequestMethod.GET) 
    public List<UserInfo> getUserList() { 
        // 处理"/users/"的GET请求,用来获取用户列表 
        // 还可以通过@RequestParam从页面中传递参数来进行查询条件或者翻页信息的传递 
        List<UserInfo> r = new ArrayList<UserInfo>(users.values()); 
        return r; 
    } 
	@ApiOperation(value="创建用户", notes="根据User对象创建用户")
    @ApiImplicitParam(name = "user", value = "用户详细实体user", required = true, dataType = "User")
    @RequestMapping(value="/", method=RequestMethod.POST) 
    public String postUser(@ModelAttribute UserInfo user) { 
        // 处理"/users/"的POST请求,用来创建User 
        // 除了@ModelAttribute绑定参数之外,还可以通过@RequestParam从页面中传递参数 
        users.put(user.getId(), user); 
        return "success"; 
    } 
	@ApiOperation(value="获取用户详细信息", notes="根据url的id来获取用户详细信息")
    @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long")
    @RequestMapping(value="/{id}", method=RequestMethod.GET) 
    public UserInfo getUser(@PathVariable Long id) { 
        // 处理"/users/{id}"的GET请求,用来获取url中id值的User信息 
        // url中的id可通过@PathVariable绑定到函数的参数中 
        return users.get(id); 
    } 
	@ApiOperation(value="更新用户详细信息", notes="根据url的id来指定更新对象,并根据传过来的user信息来更新用户详细信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long"),
            @ApiImplicitParam(name = "user", value = "用户详细实体user", required = true, dataType = "User")
    })
    @RequestMapping(value="/{id}", method=RequestMethod.PUT) 
    public String putUser(@PathVariable Long id, @ModelAttribute UserInfo user) { 
        // 处理"/users/{id}"的PUT请求,用来更新User信息 
        UserInfo u = users.get(id); 
        u.setName(user.getName()); 
        u.setAge(user.getAge()); 
        users.put(id, u); 
        return "success"; 
    } 
	@ApiOperation(value="删除用户", notes="根据url的id来指定删除对象")
    @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long")
    @RequestMapping(value="/{id}", method=RequestMethod.DELETE) 
    public String deleteUser(@PathVariable Long id) { 
        // 处理"/users/{id}"的DELETE请求,用来删除User 
        users.remove(id); 
        return "success"; 
    } 
}

SpringBoot中使用Spring Security进行安全控制

我们在编写Web应用时,经常需要对页面做一些安全控制,比如:对于没有访问权限的用户需要转到登录表单页面。要实现访问控制的方法多种多样,可以通过Aop、拦截器实现,也可以通过框架实现(如:Apache Shiro、Spring Security)。

本文将具体介绍在Spring Boot中如何使用Spring Security进行安全控制。

准备页面

Controller代码准备

@Controller
public class ThyController {
	@RequestMapping("/index")
    public String index() {
        return "test";
    }
    @RequestMapping("/hello")
    public String hello() {
        return "hello";
    }
    @RequestMapping("/login")
    public String login() {
        return "login";
    }
}

前端代码

test.html


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Spring Security入门</title>
    </head>
    <body>
        <h1>欢迎使用Spring Security!</h1>
        <p>点击 <a th:href="@{/hello}">这里</a> 打个招呼吧</p>
    </body>
</html>
hello.html


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Hello World!</title>
    </head>
    <body>
        <h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
        <form th:action="@{/logout}" method="post">
            <input type="submit" value="注销"/>
        </form>
    </body>
</html>

整合Spring Security

在这一节,我们将对/hello页面进行权限控制,必须是授权用户才能访问。当没有权限的用户访问后,跳转到登录页面。

添加依赖

Gradle:

implementation 'org.springframework.boot:spring-boot-starter-security'

Maven:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Spring Security配置

创建Spring Security的配置类WebSecurityConfig,具体如下:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER");
    }
}
  • 通过@EnableWebSecurity注解开启Spring Security的功能
  • 继承WebSecurityConfigurerAdapter,并重写它的方法来设置一些web安全的细节
  • configure(HttpSecurity http)方法
    • 通过authorizeRequests()定义哪些URL需要被保护、哪些不需要被保护。例如以上代码指定了/和/home不需要任何认证就可以访问,其他的路径都必须通过身份验证。
    • 通过formLogin()定义当需要用户登录时候,转到的登录页面。
  • configureGlobal(AuthenticationManagerBuilder auth)方法,在内存中创建了一个用户,该用户的名称为user,密码为password,用户角色为USER。

新增登录请求与页面

新增/login请求映射至login.html(前面的controller中已经设置)

login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Spring Security Example </title>
    </head>
    <body>
        <div th:if="${param.error}">
            用户名或密码错
        </div>
        <div th:if="${param.logout}">
            您已注销成功
        </div>
        <form th:action="@{/login}" method="post">
            <div><label> 用户名 : <input type="text" name="username"/> </label></div>
            <div><label> 密  码 : <input type="password" name="password"/> </label></div>
            <div><input type="submit" value="登录"/></div>
        </form>
    </body>
</html>


标题:SpringBoot系列教程(二)Web篇(下)
作者:XxwGit
地址:http://xxwgit.cn/solo/articles/2019/08/25/1566669328987.html

评论