SpringBoot是基于spring框架衍生的一種新的微服務(wù)框架迂猴,如果對(duì)Spring有一定了解的同學(xué)肯定知道在Spring中需要配置各種xml文件完成bean的注冊(cè)操作线梗,隨著服務(wù)越來越多,配置就變得越來越復(fù)雜溪胶,而SpringBoot就可以比較好的解決這個(gè)痛點(diǎn)甚纲,又例如需要搭建一個(gè)Spring MVC的環(huán)境听盖,在maven中需要手動(dòng)加入各種依賴包绞吁,但是SpringBoot卻提供了spring-boot-starter-web
可以幫我們解決開發(fā)一個(gè)Java Web項(xiàng)目的所有依賴情況
SpringBoot不是獨(dú)立于Spring存在的幢痘,SpringBoot就是把Spring的功能再次進(jìn)行包裝,對(duì)外暴露了更高層次的方法家破,使得我們?cè)谑褂玫臅r(shí)候可以省去很多配置和操作颜说,約定俗成優(yōu)于配置
,接下來就來快速學(xué)習(xí)下SpringBoot 如何使用的以及一些其他特定的功能员舵,其中有些要稍微了解下Spring的知識(shí)脑沿,感興趣的可以看看【目錄】Spring 源碼學(xué)習(xí)
項(xiàng)目demo地址 simple-springboot
目錄
10分鐘入門SpringBoot
1、Demo
2马僻、展示所有的bean信息
3、HTTP請(qǐng)求 監(jiān)控輸出
4注服、Swagger
1韭邓、Demo
如下圖就是SpringBoot的文件目錄結(jié)構(gòu)
Bootstrap 文件
整個(gè)的SpringBoot啟動(dòng)入口措近,如下@SpringBootApplication就是SpringBoot的自動(dòng)配置相關(guān)注解,@ComponentScan則是包掃描的路徑女淑,其次包含了swagger的注解瞭郑,后面再介紹
@SpringBootApplication
@ComponentScan("com.demo")
@EnableSwagger2
public class Bootstrap {
public static void main(String[] args) {
SpringApplication.run(Bootstrap.class);
// SpringBoot啟動(dòng)
}
}
BeanIoc 文件
加上@Configuration就是SpringBoot的配置,里面包含的@Bean則是類似于Spring的xml文件配置的bean一致鸭你,只是從xml文件變成了類文件
// 這個(gè)參數(shù)設(shè)置的是beanIoc這個(gè)類本身bean的自定義beanName
@Configuration("beanI")
public class BeanIoc {
@Bean
public StudentService studentS1ervice() {
// 在這里就是為了驗(yàn)證注入到spring IOC容器的名字到底是如何的屈张,所以故意加了一個(gè)1
// 通過結(jié)束bean的刷新監(jiān)聽事件打印出的beanName可以具體驗(yàn)證該操作是否可行
return new StudentService();
}
@Bean
public CustomContextEventRefresh customContextEventRefresh() {
return new CustomContextEventRefresh();
}
@Bean
public PeoplePropertiesPrefix peoplePropertiesPrefix() {
return new PeoplePropertiesPrefix();
}
@Bean("student")
public StudentServiceWithCustomConstruct studentServiceWithCustomConstruct() {
return new StudentServiceWithCustomConstruct("custom");
}
@Bean("SpringContextTool")
public SpringApplicationContextAware springApplicationContextAware() {
// 這個(gè)bean后續(xù)會(huì)重點(diǎn)關(guān)注下
return new SpringApplicationContextAware();
}
@Bean("bean1")
public Bean1 bean1() {
return new Bean1();
}
}
PeoplePropertiesPrefix 文件
和properties文件做映射處理,會(huì)自動(dòng)匹配符合的前綴
@ConfigurationProperties("people")
public class PeoplePropertiesPrefix {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
application.properties 文件
如上述的PeoplePropertiesPrefix的注解信息是people開頭袱巨,則會(huì)自動(dòng)和下面的people開頭的屬性進(jìn)行映射處理
people.name=zhangsan
people.age=18
people=hello
StudentController 文件
該文件中列舉了在HTTP請(qǐng)求中不同的參數(shù)提交方式阁谆,并且所有的方法都加上了@ResponseBody,則意味著直接以函數(shù)的返回值為HTTP請(qǐng)求的body數(shù)據(jù)填充愉老。
- 無參數(shù)的GET請(qǐng)求方式
- 帶?參數(shù)的GET請(qǐng)求方式
- 帶路徑參數(shù)的GET請(qǐng)求方式
- JSON參數(shù)的POST請(qǐng)求方式
- Map參數(shù)的POST請(qǐng)求方式
- 表單提交的POST請(qǐng)求方式
其次關(guān)于swagger以及獲取bean信息的相關(guān)點(diǎn)后面再介紹
@RequestMapping("/")
@Controller
public class StudentController {
@Resource
private StudentService studentService;
@Resource
private PeoplePropertiesPrefix peoplePropertiesPrefix;
@Resource
private SpringApplicationContextAware springApplicationContextAware;
@Value("${people}")
protected String people;
@ApiOperation("基礎(chǔ)GET請(qǐng)求")
@GetMapping("/index")
@ResponseBody
public String index() {
// 非吵÷蹋基礎(chǔ)的get請(qǐng)求
return "{\"name\":\"zhangsan\"}";
}
@ApiOperation("基礎(chǔ)POST請(qǐng)求")
@PostMapping("/index.do")
@ResponseBody
public String indexPost(@RequestBody Student student) {
// 使用json的方式去提交
String name = student.getName();
return "{\"name\":\"" + name + "\"}";
}
@ApiOperation("帶路徑參數(shù)的GET請(qǐng)求")
@GetMapping("/index2/{id}")
@ResponseBody
public String indexGet(@PathVariable String id) {
// get的方式,帶上了路徑參數(shù)
return "{\"id\":\"" + id + "\"}";
}
@ApiOperation("帶上?參數(shù)的GET請(qǐng)求")
@GetMapping("/index3/")
@ResponseBody
public String indexGetWithPar(@RequestParam String id, @RequestParam int age) {
// get的方式,帶上get請(qǐng)求的參數(shù)
Map<String, Object> map = new HashMap<>(2);
map.put("id", id);
map.put("age", age);
return JSON.toJSONString(map);
}
@ApiOperation("Map參數(shù)的POST請(qǐng)求")
@PostMapping("/indexPost")
@ResponseBody
public String indexPost2(@RequestBody Map map) {
return "{\"id\":\"" + map.get("id") + "\"}";
}
@ApiOperation("Form參數(shù)的POST請(qǐng)求")
@RequestMapping(value = "/indexPostForm", method = RequestMethod.POST)
@ResponseBody
public String indexPost3(Student student) {
// 其實(shí)content-type是application/x-www-form-urlencoded
String name = student.getName();
return "{\"name\":\"" + name + "\"}";
}
@PostMapping("indexb1")
@ResponseBody
public String indexBean1(Student student) {
Map<String, Object> map = new HashMap<>(2);
map.put("id", studentService.getName(student));
map.put("age", studentService.getAge(student));
return JSON.toJSONString(map);
}
@GetMapping("/indexp")
@ResponseBody
public String indexp() {
// 非臣等耄基礎(chǔ)的get請(qǐng)求
Map<String, Object> map = new HashMap<>(2);
map.put("name", peoplePropertiesPrefix.getName());
map.put("age", peoplePropertiesPrefix.getAge());
map.put("all", people);
return JSON.toJSONString(map);
}
@ApiOperation(value = "獲取Spring Bean信息", notes = "Spring Bean")
@GetMapping("/indexbc")
@ResponseBody
public String indexBeanCount() {
// 非逞娴粒基礎(chǔ)的get請(qǐng)求,獲取bean的信息
// 后面再介紹這個(gè)請(qǐng)求
List<String> list = new ArrayList<>();
for(String beanName: springApplicationContextAware.getBeanName()){
list.add(beanName + "\n");
}
return JSON.toJSONString(list);
}
@PostMapping("/get_request_info")
@ResponseBody
public String indexWithHeader(HttpServletRequest request, @RequestBody Map map) {
Enumeration<String> headers = request.getHeaderNames();
Map<String, Object> res = new HashMap<>(2);
res.put("requestBody", map);
Map<String, Object> requestHeader = new HashMap<>(10);
res.put("requestHeader", requestHeader);
while (headers.hasMoreElements()) {
String header = headers.nextElement();
String value = request.getHeader(header);
requestHeader.put(header, value);
}
System.out.println(JSON.toJSONString(res));
return JSON.toJSONString(res);
}
}
POM 文件
核心的POM文件
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<properties>
<java_source_version>1.8</java_source_version>
<java.version>1.8</java.version>
<java_target_version>1.8</java_target_version>
<file_encoding>UTF-8</file_encoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 和AOP 有關(guān) -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!--json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.40</version>
</dependency>
</dependencies>
好了,到現(xiàn)在整個(gè)的SpringBoot 項(xiàng)目算是完成了咒林,默認(rèn)了HTTP端口是8080熬拒,運(yùn)行Bootstrap的main方法啟動(dòng)項(xiàng)目,直到最后輸出如下日志信息
利用postman工具能夠很方便的測(cè)試我們的項(xiàng)目是否運(yùn)行正常
到這里整個(gè)的SpringBoot的demo就完成了
2垫竞、展示所有的bean信息
現(xiàn)在提一個(gè)問題澎粟,我們?cè)撊绾潍@取到Spring IOC容器所有的bean信息然后輸出到網(wǎng)頁上?
想要解決這個(gè)問題件甥,那第一點(diǎn)肯定要獲取到Spring IOC容器的上下文捌议,然后從上下文中獲取bean信息,這個(gè)可以由ApplicationContextAware接口的實(shí)現(xiàn)類完成引有,他有一個(gè)set方法瓣颅,可以注入上下文信息,然后獲取該實(shí)現(xiàn)類間接獲取到所有的bean信息就可以了譬正。
SpringApplicationContextAware 文件
public class SpringApplicationContextAware implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// 通過這種形式就獲取到了Spring 本身的上下文內(nèi)容了
// 該方法由spring在aware操作時(shí)調(diào)用宫补,此時(shí)對(duì)象本身已經(jīng)實(shí)例化了
SpringApplicationContextAware.applicationContext = applicationContext;
}
public int getBeanCount() {
// 獲取了上下文之后,調(diào)用其方法獲取bean的個(gè)數(shù)
return applicationContext.getBeanDefinitionCount();
}
public String[] getBeanName() {
return applicationContext.getBeanDefinitionNames();
}
}
然后通過@Bean的形式曾我,注入了SpringContextTool的bean對(duì)象粉怕,緊接著直接調(diào)用getBeanName方法,直接輸出即可抒巢,如下圖就是輸出的bean所有的信息
其實(shí)在demo中還有個(gè)使用
3贫贝、HTTP請(qǐng)求 監(jiān)控輸出
這個(gè)其實(shí)是使用了Spring MVC 的publishEvents參數(shù)(默認(rèn)為true),然后利用ServletRequestHandledEvent事件完成,具體可看如下的FrameworkServlet類文件
private void publishRequestHandledEvent(
HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) {
if (this.publishEvents) {
// 默認(rèn)為true
long processingTime = System.currentTimeMillis() - startTime;
int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1);
this.webApplicationContext.publishEvent(
new ServletRequestHandledEvent(this,
request.getRequestURI(), request.getRemoteAddr(),
request.getMethod(), getServletConfig().getServletName(),
WebUtils.getSessionId(request), getUsernameForRequest(request),
processingTime, failureCause, statusCode));
}
}
現(xiàn)在我們只需要設(shè)置好ServletRequestHandledEvent的事件監(jiān)聽器就行
public class CustomServletRequestHandledEventRefresh implements ApplicationListener<ServletRequestHandledEvent> {
@Override
public void onApplicationEvent(ServletRequestHandledEvent event) {
FrameworkServlet frameworkServlet = (FrameworkServlet)event.getSource();
String clientAddress = event.getClientAddress();
String desc = event.getDescription();
String methodName = event.getMethod();
String requestUrl = event.getRequestUrl();
String servletName = event.getServletName();
int statusCode = event.getStatusCode();
long time = event.getTimestamp();
System.out.println(JSON.toJSONString(event));
// 打印在控制臺(tái)上
}
}
然后注冊(cè)該bean即可,他是實(shí)現(xiàn)ApplicationListener接口的稚晚,處理為HTTP請(qǐng)求后由Spring框架自身調(diào)用完成崇堵,輸出的結(jié)果如下圖,還可以設(shè)置異步的線程池異步處理該事件客燕,更多的可以看看
4鸳劳、Swagger
swagger是一個(gè)第三方的工具,更多可參考Swagger 官網(wǎng)也搓,這里我們忽略其編輯器的功能赏廓,關(guān)注其界面化的展示最新的API接口文檔并可以進(jìn)行調(diào)用測(cè)試的功能。
POM設(shè)置
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
Swagger Bean 設(shè)置
@Bean("swaggerDocker")
public Docket docket() {
ApiInfo apiInfo = new ApiInfoBuilder()
.title("Spring Boot Swagger DEMO")
.description("學(xué)習(xí)swagger")
.version("1.0")
.build();
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo)
.select()
.apis(RequestHandlerSelectors.basePackage("com.demo"))
// API 掃描的包路徑傍妒,一般建議是controller一層即可
.paths(PathSelectors.any())
.build();
}
Controller 設(shè)置
目前只介紹ApiOperation幔摸,其實(shí)還有不少參數(shù),更多自行查看官網(wǎng)文檔
@ApiOperation(value = "獲取Spring Bean信息", notes = "Spring Bean")
// 設(shè)置函數(shù)的標(biāo)題拍顷,以及其描述信息
最后在Bootstrap文件加上@EnableSwagger2
就完成了整個(gè)的Swagger 工具接入抚太,輸入http://127.0.0.1:8080/swagger-ui.html#/student-controller,可以看到如下圖的接口文檔
到此整個(gè)的SpringBoot的入門使用就完成了昔案。