spring boot入门

spring boot的定位

Spring Boot并不是不对Spring功能上的增强,而是提供了一种快速使用Spring的方式

本节转载自spring boot与spring mvc的区别是什么?

Spring Boot与spring及spring mvc的关系

简介

  • Spring 框架就像一个家族,有众多衍生产品例如 boot、security、jpa等等。但他们的基础都是Spring 的 IOC(提供了依赖注入的容器)和 AOP(解决了面向横切面的编程) ,然后在此两者的基础上实现了其他延伸产品的高级功能
  • Spring MVC是基于 Servlet 的一个 MVC 框架 主要解决 WEB 开发的问题
  • 因为 Spring 的配置非常复杂,各种XML、 JavaConfig、hin处理起来比较繁琐。于是为了简化开发者的使用,从而创造性地推出了Spring boot,约定优于配置,简化了spring的配置流程

关系

  1. Spring 最初利用“工厂模式”(DI)和“代理模式”(AOP)解耦应用组件。
  2. 大家觉得挺好用,于是按照这种模式搞了一个 MVC框架(一些用Spring 解耦的组件),用开发 web 应用( SpringMVC )。
  3. 然后有发现每次开发都写很多样板代码,为了简化工作流程,于是开发出了一些“懒人整合包”(starter),这套就是 Spring Boot。

所以,用最简练的语言概括就是:
Spring 是一个“引擎”;
Spring MVC 是基于Spring的一个 MVC 框架 ;
Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。
spring mvc < spring <springboot

为什么用spring boot

功能

Spring Boot实现了自动配置,降低了项目搭建的复杂度。
众所周知Spring框架需要进行大量的配置,Spring Boot引入自动配置的概念,让项目设置变得很容易。Spring Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box),大部分的Spring Boot应用都只需要非常少量的配置代码,开发者能够更加专注于业务逻辑。

Spring Boot只是承载者,辅助你简化项目搭建过程的。如果承载的是WEB项目,使用Spring MVC作为MVC框架,那么工作流程和你上面描述的是完全一样的,因为这部分工作是Spring MVC做的而不是Spring Boot。

对使用者来说,换用Spring Boot以后,项目初始化方法变了,配置文件变了,另外就是不需要单独安装Tomcat这类容器服务器了,maven打出jar包直接跑起来就是个网站,但你最核心的业务逻辑实现与业务流程实现没有任何变化

优点

  • Spring Boot可以建立独立的Spring应用程序
  • 内嵌了如Tomcat,Jetty和Undertow这样的容器,也就是说可以直接跑起来,用不着再做部署工作了
  • 可以自动配置Spring:无需再像Spring那样搞一堆繁琐的xml文件的配置
  • 提供了一些现有的功能,如量度工具,表单数据验证以及一些外部配置这样的一些第三方功能
  • 提供的POM可以简化Maven的配置

spring Boot实例demo

程序入口

SpringApplication.run(App.class, args)

首先来创建src/main/java/ToutiaoApplication.java:

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

程序的入口:SpringApplication.run(Application.class, args),SpringApplication是Spring Boot框架中描述Spring应用的类,它的run()方法会创建一个Spring应用上下文(Application Context)
另一方面它会扫描当前应用类路径上的依赖,如果Spring Boot判断这是一个Web应用,会启动一个内嵌的Servlet容器(默认是Tomcat)用于处理HTTP请求。

@SpringBootApplication

Spring Boot提供一个方便的 @SpringBootApplication 选择。该 @SpringBootApplication 注解等价于以默认属性使用 @Configuration+@EnableAutoConfiguration+@ComponentScan

1. @Configuration

定义一个配置类,用@Configuration注解该类,等价于XML中配置beans;用@Bean标注方法等价于XML中配置bean

public class SpringConfig {  

    @Bean  
    public Piano piano(){  
        return new Piano();  
    }  
    @Bean(name = "counter")   
    public Counter counter(){  
        return  new Counter(12,"Shake it Off",piano());  
    }  
} 

2. @EnableAutoConfiguration

启动Spring MVC

3. @ComponentScan

启用组件扫描

实现Hello World显示

在controller目录下创建一个IndexController 类(之后的方法除特殊说明,否则都是IndexController类中的方法)

@Controller
public class IndexController {
    @RequestMapping(path = {"/","/index"})
    @ResponseBody
    public String index(HttpSession session){
        return "Hello World" ;
    }
}

运行Application文件,右键Run As -> Java Application,之后打开浏览器输入地址:http://127.0.0.1:8080/(或者http://127.0.0.1:8080/ index) 就可以看到Hello world。

@Controller

基于@Component注解,表明是控制类组件,辅助实现组件扫描,组件扫描会自动找到@Controller注解对应的类,并将其声明为Spring应用上下文的一个bean

@RequestMapping(value=”/”,method)

  • 作用
    @RequestMapping 注解为控制器指定可以处理那些URL 请求

@RequestMapping (value=”/”,method),value值属性指定了这个方法所要处理的请求路径,method属性细化了它所处理的HTTP方法(GET或者POST),例如

@RequestMapping(value = "/login", method = RequestMethod.POST)

获取请求中信息

  • @RequestBody
    绑定请求对象,Spring会帮你进行协议转换,将Json、Xml协议转换成你需要的对象。
  • @ResponseBody
    标注任何对象,由Srping完成对象——协议的转换
    在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换,底层这种灵活的消息转换机制,就是Spring3.x中新引入的HttpMessageConverter即消息转换器机制。
    //value与path都是别名,实质上是一样的
    @RequestMapping(value = {"/profile/{groupId}/{userId}"})
    @ResponseBody
    //127.0.0.1:8080/profile/12/33?key=xx&type=33
    public String profile(
    @PathVariable("groupId") String groupId,
    @PathVariable("userId") int userId,
    @RequestParam(value = "key",defaultValue = "megustas") String key,
    @RequestParam(value = "type",defaultValue = "1") int type) {
        return String.format("GID{%s},UID{%d},KEY{%s},TYPE{%d}",groupId,userId,key,type);
    }

@RequestParam注解和@PathVariable注解的区别,从字面上可以看出前者是获取请求里边携带的参数;后者是获取请求路径里边的变量参数。

例如:

127.0.0.1/user/{userId}?userName=datiangou
  • userId是路径上的变量
  • userName才是请求参数信息

@Pathvariable

通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的{xxx}占位符可以通过@PathVariable("xxx") 绑定到操作方法的入参中。

@RequestMapping("/pathVariable/{name1}")
public String pathVariable(@PathVariable("name1")String name2){
    System.out.println("hello "+name2);
    return "helloworld";
}

URL 中的{name1}占位符通过@PathVariable("name1") 绑定到操作方法的String name2入参中。

@RequestParam

获取请求参数

模板

直接返回HTML代码太复杂

在之前所有的@RequestMapping注解的方法中,返回值字符串都被直接传送到浏览器端并显示给用户。但是为了能够呈现更加丰富、美观的页面,我们需要将HTML代码返回给浏览器,浏览器再进行页面的渲染、显示。

一种很直观的方法是在处理请求的方法中,直接返回HTML代码,但是这样做的问题在于——一个复杂的页面HTML代码往往也非常复杂,并且嵌入在Java代码中十分不利于维护。更好的做法是将页面的HTML代码写在模板文件中(此处使用Velocity模板语言),渲染后再返回给用户。

模板引擎

模板引擎是为了使用户界面与业务数据分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。

在MVC模式中,模板引擎的工作原理基本一样,比如说以freemarker为例,如下图:

模板 + 数据模型 = 输出

可概括为一个公式:

模板 + 数据模型 = 输出

    @RequestMapping(value = {"/vm"})
    public String news(Model model){
        model.addAttribute("value1", "vv1");
        List<String> colors = Arrays.asList(new String[]{"RED", "GREEN", "BLUE"});
        Map<String, String> map = new HashMap<String, String>();
        for (int i = 0; i < 4; ++i) {
            map.put(String.valueOf(i), String.valueOf(i * i));
        }
        model.addAttribute("colors", colors);
        model.addAttribute("map", map);
        model.addAttribute("user",new User("Megustas"));//传递自定义对象  
        return "news";//news.vm
    }

Model

后端与渲染之间铰链的一个数据模型Model,通过Model向前台视图传递参数,Model中存入的数据在Velocity中直接使用

return "news";

返回值不再是ResponseBody,
在上述例子中,返回值”news”并非直接将字符串返回给浏览器,而是寻找名字为news的模板进行渲染,news.vm文件存放于resources/templates目录下

Velocity简单语法

1.标识Velocity的脚本语句 #

用来标识Velocity的脚本语句,包括#set、#if 、#else、#end、#foreach、#end、#iinclude、#parse、#macro等

2. 用来标识一个变量$

3. 把不存在的变量显示为空白!

4. 注释##

5. 常用指令

常用指令 说明 例子
#include include指令用于引入其他的文件,引入的文件将会被当做静态文件来处理 #include("test1.txt")
#parse 引入的文件通常是动态文件,并且parse指令中允许嵌套  
#set 赋值指令:可以用于创建一个新的实例,或者更新一个已经存在的实例。set指令中也支持基本的数据运算 #set($username="yxd")
#if #else #end 条件判断指令  
#foreach #end 循环指令 #foreach ($item in [1..5]).. #end
#macro #end 提供了一个构建模板代码复用的机制,类似于Java中的函数 #macro ( sayHi $username)Hello $username #end

request/response

一次网页请求中,通过request获取它的所有数据

    @RequestMapping(value = {"/request"})
    @ResponseBody
    public String request(HttpServletRequest request,
                          HttpServletResponse response,
                          HttpSession session){
        //获取Http请求的头文件
        StringBuilder sb = new StringBuilder();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()){
            String name = headerNames.nextElement();
            sb.append(name + ":" + request.getHeader(name) + "<br>");
        }

        for(Cookie cookie : request.getCookies()){
            sb.append("Cookie");
            sb.append(cookie.getName());
            sb.append(":");
            sb.append(cookie.getValue());
            sb.append("<br>");
        }

        sb.append("getMethod:" + request.getMethod()+ "<br>");
        sb.append("getPathInfo:" + request.getPathInfo()+ "<br>");
        sb.append("getQueryString:" + request.getQueryString()+ "<br>");
        sb.append("getRequestURI" + request.getRequestURI());

        return sb.toString();
    }

Enumeration

Enumeration接口作用和Iterator类似,提供了遍历元素的功能,其中只定义了两种方法:

方法 作用
boolean hasMoreElements() 测试Enumeration对象中是否包含元素,如果有返回true,则表示至少包含一个元素
Object nextElement() 如果Enumeration对象还有元素,返回对象的下一个元素,否则抛出NoSuchElementException

request.getQueryString():

request.getQueryString()就是获取查询字符串
即请求?后面的就是QueryString,例如

127.0.0.1:8080/request?type=2&&k=xx
  • QueryString为type=2&&k=xx
  • RequestURI为/request

response

可以通过HttpServletResponse response将更多数据写回

@RequestMapping(value = {"/response"})
@ResponseBody
public String response(
            @CookieValue(value="nowcoderid",defaultValue = "a") String nowcoderId,
            @RequestParam(value = "key", defaultValue = "key") String key,
            @RequestParam(value = "value", defaultValue = "value") String value,
            HttpServletResponse response){
    response.addCookie(new Cookie(key,value));
    response.addHeader(key,value);
    return "NowCoderId From Cookie:" + nowcoderId;
}

访问:127.0.0.1:8080/response
输出:NowCoderId From Cookie:a(此时为默认值)

访问127.0.0.1:8080/response?key=nowcoderid&value=22:
输出:NowCoderId From Cookie:22

重定向

redirect前缀,跳到首页,默认是302跳转
从一个页面跳到另一个页面,所有的访问都是同一个HttpSession,可以在redirect中添加session的一些特性,返回到首页的时候,把session的信息读取出来,显示在首页。用户体验较好。

301和302的区别
301:永久转移
如果是301,会把信息存入浏览器,下次浏览器访问网址,会直接定位到另一个地方。
302:临时转移

统一的异常处理

@ExceptionHandler

  • 统一处理某一类异常,从而能够减少代码重复率和复杂度
  • @ExceptionHandler只会是在当前的Controller里面起作用
    @RequestMapping("/admin")
    @ResponseBody
    public String admin(@RequestParam(value = "key",required = false) String key){
        if("admin".equals(key)){
            return "hello admin";
        }
        throw new IllegalArgumentException("Key 错误");
    }
    //好处是可以用统一的页面处理问题
    @ExceptionHandler()
    @ResponseBody
    public String error(Exception e){
        return "error:" + e.getMessage();
    }

@ControllerAdvice

如果想所有的Controller统一处理异常的话,可以用@ControllerAdvice来创建一个专门处理的类,这样所有控制器的异常可以在一个地方进行处理

@ResponseStatus

  • 可以将某种异常映射为HTTP状态码
  • 不要轻易把@ResponseStatus修饰目标方法,因为无论它执行方法过程中有没有异常产生,用户都会得到异常的界面,而目标方法正常执行

官方文档

快速生成空项目文件

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容