Spring Boot实战
来源:互联网 发布:淘宝店铺收藏链接生成 编辑:程序博客网 时间:2024/05/19 13:13
Spring在java EE开发中是实际意义上的标准,但我们在开发Spring的时候可能会遇到以下令人头疼的问题:
1.大量配置文件的定义。
2.与第三方软件整合的技术问题。
Spring每个版本的退出都以减少配置作为自己的主要目标,例如:
1.推出@Component,@Service,@Repository,@Controller注解在类上声明Bean
2.推出@Configuration,@Bean的java配置来替代xml配置。
Spring Boot具有以下特征:
1.遵循“习惯优于配置”的原则,使用Spring Boot只需要很少的配置。大部分可以使用默认配置。
2.项目快速搭建,可无配置整合第三方框架。
3.可完全不使用xml配置,只使用自动配置和java config。
4.内嵌servlet容器,应用可用jar包运行。
5.运行中应用状态的监控。
虽然Spring Boot给我们带来了类似于脚本语言开发的效率,但Spring Boot里没有使用如何让你意外的技术,完全是一个单纯的基于Spring的应用。如,Spring Boot的自动配置是通过Spring 4.x 的@Conditional注解来实现的。
第一部分.点睛Spring 4.x
Chapter1.Spring基础
Spring的简史:
1.xml配置
在Spring 1.x时代,使用Spring开发满眼都是xml配置的Bean,随着项目的扩大,我们需要xml配置文件分放到不同的配置文件里,那时候需要频繁地在开发的类和配置文件中切换。
2.注解配置
在Spring 2.x时代,随着JDK 1.5带来的注解支持,Spring提供了声明Bean的注解(如@Component,@Service),大大减少了配置量。这时Spring圈子里存在着一种争论:注解配置和xml配置究竟哪个好?我们最终的选择是应用的基本配置(如数据库配置)用xml,业务配置用注解。
3.java配置
Spring3.x到现在,Spring提供了java配置的能力,使用java配置可以让你更理解你配置的Bean。我们目前刚好处于这个时代,Spring 4.x和Spring Boot都推荐使用java配置,所以我们在本书通篇将使用java配置。
Spring使用简单的POJO(plain old java object,即无任何限制的普通java对象)来进行企业化开发,每一个被Spring管理的java对象都称之为Bean。而Spring提供了一个IoC容器用来初始化对象,解决对象间的依赖管理和对象的使用。
Spring的生态:
1.Spring Boot:使用默认开发配置来实现快速开发
2.Spring Data:对主流的关系型和NoSQL数据库的支持
3.Spring Security:通过认证和授权保护应用
4.Spring Web Flow:基于Spring MVC提供基于向导流程式的Web应用开发
5.Spring Web Services:提供了基于协议有限的SOAP/Web服务
6.Spring Session:提供一个API及实现来管理用户会话信息
等等,还有很多。
Spring框架本身有四大原则:
1.使用POJO进行轻量级和最小侵入式开发
2.通过依赖注入和基于接口编程实现松耦合
3.通过AOP和默认习惯进行声明式编程
4.通过AOP和模板(template)减少模块化代码
我们经常说的控制翻转(inversion of control-IOC)和依赖注入(dependency injection-DI)在Spring环境下是等同的概念,控制翻转是通过依赖注入实现的。所谓的依赖注入指的是容器负责创建对象和维护对象间的依赖关系,而不是通过对象本身自己的创建和解决自己的依赖。比如典型的:
@AutowiredMyBean bean;
而不是自己new出一个对象
声明Bean的注解:
1.@Component组件,没有明确的角色
2.Service在业务逻辑层(service层)使用
3.@Repository在数据访问层(dao层)使用
4.@Controller在展现层(MVC->Spring MVC)使用
注入Bean的注解:
1.@Autowired,Spring提供的注解(推荐使用)
2.@Inject,JSR-330提供
3.@Resource,JSR-250提供
注入Bean的注解可以注解在set方法上或者属性上,不过最好是在属性上,优点是代码更少,层次更清晰。
@Configuration声明当前类是一个配置类。
使用@ComponentScan,自动扫描包名下所有使用@Service,@Component,@Compository,@Controller的类,并注册为Bean。
java配置是通过@Configuation和@Bean来实现的。
@Configuration声明当前类时一个配置类,相当于一个Spring配置的xml文件。
@Bean注解在方法上,声明当前方法的返回值为一个Bean。
何时使用java配置或者注解配置呢?
我们的原则是:全局配置使用java配置(如数据库相关配置,MVC相关配置),业务Bean的配置使用注解配置。
AOP:面向切面编程,相对于OOP面向对象编程
Spring的AOP的存在的目的是为了解耦。AOP可以让一组类共享相同的行为。在OOP中只能通过继承类和实现接口,来使代码的耦合度增强,且类继承只能为单继承,阻碍更多行为添加到一组类上,AOP弥补了OOP的不足。
注解:注解本身是没有功能的,就和xml一样。注解和xml都是一种元数据,元数据即解释数据的数据,这就是所谓的配置。
Chapter2.Spring常用配置
Scope描述的是Spring容器如何新建Bean的实例的。有以下几种,通过@Scope注解来实现:
1.Singleton:一个Spring容器中只有一个Bean的实例,此为Spring的默认配置,全容器共享一个实例。
2.Prototype:每次调用新建一个Bean的实例。
3.Request:Web项目中,给每一个http request新建一个Bean实例。
4.Session:Web项目中,给每一个http session新建一个Bean实例。
Spring EL-Spring表达式语言,支持在xml和注解中使用表达式,类似于JSP的EL表达式语言。
示例:
//注入普通字符串@Value("I Love You!") //1private String normal;//注入操作系统属性@Value("#{systemProperties['os.name']}") //2private String osName;//注入表达式结果@Value("#{ T(java.lang.Math).random() * 100.0 }") //3private double randomNumber;
在实际开发的时候,经常会遇到Bean在使用使用之前或者之后做些必要的操作。在使用java配置和注解配置下提供了如下两种方式:
1.java配置方式:使用@Bean的initMethod和destroyMethod
2.注解方式:利用JSR-250的@PostConstruct和@PreDestroy
Spring的事件(Application Event)为Bean与Bean之间的消息通信提供了支持。当一个Bean处理完一个任务之后,希望另外一个Bean知道并能做相应的处理,这时我们就需要让另一个Bean监听当前Bean说发送的事件。
Spring的事件需要遵循如下流程:
1.自定义事件,继承ApplicationEvent
2.定义事件监听器,实现ApplicationListener
3.使用容器发布事件
具体例子看书籍源码即可。
Chapter3.Spring高级话题
Spring的依赖注入的最大亮点就是你所有的Bean对容器Spring容器的存在是没有意识的。即你可以将你的容器替换成别的容器。
但在实际项目中,不可避免要用到Spring容器本身的功能资源,这时你的Bean必须要意识到Spring容器的存在,才能调用Spring说提供的资源,这就是所谓的Spring Aware。其实,Spring Aware本来就是Spring设计用来框架内部使用的,若使用了Spring Aware,你的Bean将会和Spring框架耦合。
Spring Aware的目的是为了让Bean获得Spring容器的服务。
多线程:
Spring通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。而实际开发中任务一般是非阻碍的,即异步的,所以我们要在配置类中通过@EnableAsync开启对异步任务的支持。并通过在实际执行的Bean方法中使用@Async注解来声明其是一个异步任务。
计划任务:
计划任务在Spring中的实现变得异常的简单。首先通过在配置类注解@EnableScheduling来开启对计划任务的支持,然后在要执行任务的方法上注解@Scheduled,声明这是一个计划任务。
Spring通过@Scheduled支持多种类型的计划任务,包含cron,fixDeley,fixedRate等。例如:
//每个5秒执行一次@Scheduled(fixedRate=5000)//UNIX或LINUX系统下的定时任务@Scheduled(cron="0 28 11 ? * *")
组合注解和元注解:
注解的大量使用,尤其相同的多个注解用到各个类或方法中,会相当繁琐。这就是所谓的样板代码,是Spring设计原则中要消除的代码。
所谓元注解其实就是可以注解到别的注解上的注解,被注解的注解称之为组合注解。
@Enable*注解:
通过观察@Enable*注解的源码,我们发现所有的注解都有一个@Import注解,@Import是用来导入配置类的,这也就意味着这些自动开启的实现其实是导入了一些自动配置的Bean。这些导入的配置主要分为三种类型:
1.直接导入配置类
2.依据调价选择配置类
3.动态注册Bean
第二部分.点睛Spring MVC 4.x
Chapter4.Spring MVC基础
分清MVC和三层架构的不同:
MVC:Model+View+Controller(数据模型+视图+控制器)
三层架构:Presentation tier+Application tier+Data tier(展现层+应用层+数据访问层)
实际的MVC只存在三层架构中的展现层,M实际上是数据模型,是包含数据的对象。在Spring MVC中,有一个专门的类叫Model,用来和V之间的数据交互、传值;V指的是视图页面,包含JSP,Thymeleaf等。C当然就是控制器(Spring MVC的注解@Controller类)。
//Spring MVC配置@Configuration@EnableWebMvc@EnableScheduling@ComponentScan("com.wisely.highlight_springmvc4")public class MyMvcConfig extends WebMvcConfigurerAdapter { @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/classes/views/"); viewResolver.setSuffix(".jsp"); viewResolver.setViewClass(JstlView.class); return viewResolver; }}
注意这里对路径前缀的配置为/WEB-INF/classes/views/,不是和我们的开发的目录一样。因为看到的页面效果是运行时而不是开发时的代码,运行时代码会将我们的页面自动编写到/WEB-INF/classes/views/(因为我把JSP文件放在了/resources/views目录下)下。
@Controllerpublic class HelloController { @RequestMapping("/index") public String hello(){ return "index"; }}
通过上面的ViewResolver的Bean配置,返回值为index,说明我们的页面放置的路径为/WEB-INF/classes/views/index.jsp。
Spring MVC的常用注解:
1.@Controller
2.@RequestMapping
3.@RequestBody
@RequestBody允许request的参数在request体中,而不是在直接链接在地址后面。
4.@ResponseBody
@ResponseBody支持将返回值放在response体内,而不是返回一个页面。
5.@PathVariable
6.@RestController
是一个组合注解,组合了@Controller和@ReponseBody。
示例:
添加jackson即相关依赖,获得对象和json或xml之间的转化。
特别指出:在实际项目中,我们主要支持json数据,没必要同时支持json和xml,因为json比xml更简洁,而且也更推荐。
public class DemoObj { private Long id; private String name; //jackson对对象和json做转换时一定需要此空构造 public DemoObj() { super(); } public DemoObj(Long id, String name) { super(); this.id = id; this.name = name; } 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; }}
演示@Controller控制器:
@Controller // 1@RequestMapping("/anno") //2public class DemoAnnoController { @RequestMapping(produces = "text/plain;charset=UTF-8") // 3 public @ResponseBody String index(HttpServletRequest request) { // 4 return "url:" + request.getRequestURL() + " can access"; } @RequestMapping(value = "/pathvar/{str}", produces = "text/plain;charset=UTF-8")// 5 public @ResponseBody String demoPathVar(@PathVariable String str, //3 HttpServletRequest request) { return "url:" + request.getRequestURL() + " can access,str: " + str; } @RequestMapping(value = "/requestParam", produces = "text/plain;charset=UTF-8") //6演示常规的request参数获取,访问路径 //为/anno/requestParam?id=1 public @ResponseBody String passRequestParam(Long id, HttpServletRequest request) { return "url:" + request.getRequestURL() + " can access,id: " + id; } @RequestMapping(value = "/obj", produces = "application/json;charset=UTF-8") //演示解释参数到对象,访问路径为/anno/obj?id=1&name=xx @ResponseBody //8 public String passObj(DemoObj obj, HttpServletRequest request) { return "url:" + request.getRequestURL() + " can access, obj id: " + obj.getId()+" obj name:" + obj.getName(); } @RequestMapping(value = { "/name1", "/name2" }, produces = "text/plain;charset=UTF-8")//9 public @ResponseBody String remove(HttpServletRequest request) { return "url:" + request.getRequestURL() + " can access"; }}
演示@RestController控制器:
@RestController //1@RequestMapping("/rest")public class DemoRestController { @RequestMapping(value = "/getjson", produces={"application/json;charset=UTF-8"}) //2 public DemoObj getjson (DemoObj obj){ //直接返回对象,对象会自动转换称json return new DemoObj(obj.getId()+1, obj.getName()+"yy"); } @RequestMapping(value = "/getxml", produces={"application/xml;charset=UTF-8"})//4返回数据的媒体类型为xml public DemoObj getxml(DemoObj obj){ return new DemoObj(obj.getId()+1, obj.getName()+"yy"); }}
Spring MVC的基本配置:
Spring MVC的定制配置需要我们的配置类继承一个WebMvcConfigureAdapter类,并在此类使用@EnableWebMvc注解,来开启对Spring MVC的配置支持,这样我们就可以重写这个类的方法,完成我们的常用配置。
静态资源映射:
@Configuration//1开启Spring MVC支持,若无此句,重写//WebMvcConfigurerAdapter方法无效@EnableWebMvc@EnableScheduling@ComponentScan("com.wisely.highlight_springmvc4")public class MyMvcConfig extends WebMvcConfigurerAdapter {// 2重写方法进行配置 @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/classes/views/"); viewResolver.setSuffix(".jsp"); viewResolver.setViewClass(JstlView.class); return viewResolver; } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) {//addResourceLocations指的是文件放置的目录,//addResourceHandler指的是对外暴露的访问路径registry.addResourceHandler("/assets/**").addResourceLocations( "classpath:/assets/"); }}
快捷的ViewController:
我们在配置页面转向的时候使用下面的代码:
@RequestMapping("/index")public Stirng hello(){return "hello";}
如果只是单纯的转向,没有其他的业务逻辑的话,这样写很麻烦,我们可以通过重写addViewControllers来简化配置:
@overridepublic void addViewControllers(ViewControllerRegistry registry){registry.addViewController("/index").setViewName("index")}
文件上传配置:
在Spring的控制器中,通过MultipartFile file来接收文件,通过MultipartFile[] files接收多个文件上传。
服务器端推送技术:
服务器推送技术在日常生活中较为常用,很多人早期的方案是使用Ajax向服务器轮询消息,这种方式的轮询频率不好控制,所以大大增加了服务器的压力。
本节的服务器端推送方案都是基于:当客户端向服务端发送请求,服务端会抓住这个请求不放,等有数据更新的时候才返回给客户端,当客户端接收到消息后,再向服务端发送请求,周而复始。这种方式的好处是大大减少了服务器的请求数量,大大减少了服务器的压力。
Spring MVC的测试:
为了测试Web项目通常不需要启动项目,我们需要一些Servlet相关的模拟对象。比如:MockMVC,MockHttpServletRequest,MockHttpServletResponse,MockHttpSession等。
测试驱动开发(TDD):
我们按照需求先写一个自己预期结果的测试用例,这个测试用例刚开始肯定是失败的测试,随着不断的编码和重构,最终让测试用例通过测试。这样才能保证软件的质量和可控性。
我们主要借助的是JUnit来进行测试。
演示测试:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = {MyMvcConfig.class})@WebAppConfiguration("src/main/resources") //1public class TestControllerIntegrationTests { private MockMvc mockMvc; //2 @Autowired private DemoService demoService;//3 @Autowired WebApplicationContext wac; //4 @Autowired MockHttpSession session; //5 @Autowired MockHttpServletRequest request; //6 @Before //7在测试开始前进行的初始化工作 public void setup() { mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); //2 } @Test public void testNormalController() throws Exception{ mockMvc.perform(get("/normal")) //8 .andExpect(status().isOk())//9 .andExpect(view().name("page"))//10 .andExpect(forwardedUrl("/WEB-INF/classes/views/page.jsp"))//11 .andExpect(model().attribute("msg", demoService.saySomething()));//12 } @Test public void testRestController() throws Exception{ mockMvc.perform(get("/testRest")) //13 .andExpect(status().isOk()) .andExpect(content().contentType("text/plain;charset=UTF-8"))//14 .andExpect(content().string(demoService.saySomething()));//15 }}
第三部分.实战Spring Boot
Chapter5.Spring基础
Spring Boot:
它使用”习惯优于配置”(项目中存在大量的配置,此外还内置一个习惯性的配置,让你无须手动进行配置)的理念让你的项目快速运行起来。使用Spring Boot很容易创建一个独立运行(运行jar,内嵌servlet容器),准生产级别的给予Spring框架的项目,使用Spring Boot你可以不用或者只需很少的Spring配置。
Spring Boot核心功能:
1.独立运行的Spring项目
2.内嵌Servlet容器
3.提供starter简化Maven配置
这个确实很方便,不用自己手动添加很多依赖
4.自动配置Spring
Spring Boot会根据在类路径中的jar包,类,为jar包里的类自动配置bean,这样会极大地减少我们要使用的配置。当然,Sping Boot只是考虑了大多数的开发场景,并不是所有的场景,若在实际中需要自动配置Bean,而Spring Boot没有提供支持,那么可以自定义自动配置。(见Spring运行原理)
5.准生产的应用监控
Spring提供基于http,ssh,telnet对运行时的项目进行监控
6.无代码生成和xml配置
Spring 4.x提倡使用java配置和注解配置组合,而Spring Boot不需要任何xml配置即可实现Spring的所有配置。
一个小技巧:
在InteliJ IDEA中创建Spring项目时,选择新建Spring Initializer项目,可以添加各种starter,然后会在maven中自动添加依赖,很方便。
@SpringBootApplication是Spring Boot项目的核心注解,主要目的是开启自动配置。
Chapter6.Spring Boot核心
@SpringBootApplication是个组合注解,源码如下:
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class})})
Spring Boot的配置文件:
Spring Boot使用一个全局的配置文件application.properties或application.yml,放置在/src/main/resources目录或者类路径下的/config下。这里面的配置非常多,参见官方给出的附录。例如:
//将tomcat默认端口号8080改为9090,并将默认的访问路径"/"//修改为"//hellohost"server.port=9090server.context-path=/hellohost
常规属性配置:
我们之前讲过在常规Spring环境下,注入properites文件里的值的方式,通过@PropertySource指明properties文件的位置,然后通过@Value注入值。在Spring Boot里,我们只需在application.properties中定义属性,然后使用@Value注入即可。
类型安全的配置(基于properties):
上例中使用@Value注入每个配置在实际项目中会显得很麻烦,因为要写@Value注入很多次啊。
下面是一个进化版,能够通过@ConfigurationProperties将properties属性和一个Bean及其属性关联,从而实现类型安全的配置。例如:在application.properties上添加:
author.name =zengauthor.age = 24
当然也可以新建一个properties文件,这就需要我们在@ConfigurationProperties的属性locations里面指定properties的位置,且需要在入口类上配置。
类型安全的Bean:
@Component@ConfigurationProperties(prefix = "author") //1 public class AuthorSettings { private String name; private Long age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Long getAge() { return age; } public void setAge(Long age) { this.age = age; }}
通过prefix指定配置的前缀,通过locations制定文件的位置。比如:
@ConfigurationProperties(prefix = "author",locations={"classpath:config/author.properties"})
日志配置:
默认情况下,Spring Boot使用Logback作为日志框架。
# LOGGINGlogging.config= # Location of the logging configuration file. For instance `classpath:logback.xml` for Logbacklogging.exception-conversion-word=%wEx # Conversion word used when logging exceptions.logging.file= # Log file name. For instance `myapp.log`logging.level.*= # Log levels severity mapping. For instance `logging.level.org.springframework=DEBUG`logging.path= # Location of the log file. For instance `/var/log`logging.pattern.console= # Appender pattern for output to the console. Only supported with the default logback setup.logging.pattern.file= # Appender pattern for output to the file. Only supported with the default logback setup.logging.pattern.level= # Appender pattern for log level (default %5p). Only supported with the default logback setup.logging.register-shutdown-hook=false # Register a shutdown hook for the logging system when it is initialized.
Spring Boot运行原理:
在前面我们了解到Spring 4.x提供了基于条件来配置Bean的能力,其实Spring Boot的神奇的实现也是基于这一原理的。
关于Spring Boot的运作原理,还是要回归到@SpringBootApplication注解上来,这个注解是一个组合注解,前面已经演示过了,它的核心功能是由@EnableAutoConfiguration注解来提供的。
Chapter7.Spring Boot的Web开发
Spring Boot提供了spring-boot-starter-web为Web开发予以支持,spring-boot-starter-web为我们提供了嵌入的Tomcat以及Spring MVC的依赖。而Web相关的自动配置存储在org.springframework.web下。从这些文件名可以看出:
1.ServerPropertiesAutoConfiguration和ServerPropertes自动配置内嵌的Servlet容器
2.HttpEncodingAutoConfiguration和HttpEncodingProperties用来自动配置http的编码
3.MultipartAutoConfiguration和MultipartProperties用来自自动配置上传文件的属性
4.JacksonHttpMessageConvertersConfiguration用来自动配置mappingJackson2HttpMessageConverter和mappingJackson2XmlHttpMessageConverter。
5.WebMvcAutoConfiguration和WebMvcProperties配置Spring MVC。
Thymeleaf与Spring MVC的集成:
@Beanpublic TemplateResolver templateResovler(){ TemplateResovler templateResovler = new ServletContextTemplateResovler(); templateResovler.setPrefix("/WEB-INF/templates"); templateResovler.setSuffix(".html"); templateResovler.setTemplateMode("HTML5"); return templateResovler;}@Beanpublic SpringTemplateEngine templateEngine(){ SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResovler(templateResovler()); return templateEngine;}@Beanpublic ThymeleafViewResovler thymeleafVewResolver(){ ThymeleafViewResolver thymeleafVewResolver = new ThymeleafViewResovler(); ThymeleafViewResovler.setTemplateEngine(templateEngine()); return ThymeleafViewResovler;}
在Spring MVC中虽然有引擎,让配置变得不那么麻烦,但还是太繁琐了啊。看看Spring Boot吧。
Thymeleaf与Spring Boot的集成:
上一部分的一切配置在Spring Boot中一切都是不需要的。Spring Boot通过org.springframework.boot.autoconfigure.thymeleaf包对Thymeleaf进行了自动配置。我们只需要在application.properties中进行适当的配置即可:
# THYMELEAF (ThymeleafAutoConfiguration)spring.thymeleaf.cache=true # Enable template caching.spring.thymeleaf.check-template=true # Check that the template exists before rendering it.spring.thymeleaf.check-template-location=true # Check that the templates location exists.spring.thymeleaf.content-type=text/html # Content-Type value.spring.thymeleaf.enabled=true # Enable MVC Thymeleaf view resolution.spring.thymeleaf.encoding=UTF-8 # Template encoding.spring.thymeleaf.excluded-view-names= # Comma-separated list of view names that should be excluded from resolution.spring.thymeleaf.mode=HTML5 # Template mode to be applied to templates. See also StandardTemplateModeHandlers.spring.thymeleaf.prefix=classpath:/templates/ # Prefix that gets prepended to view names when building a URL.spring.thymeleaf.suffix=.html # Suffix that gets appended to view names when building a URL.spring.thymeleaf.template-resolver-order= # Order of the template resolver in the chain.spring.thymeleaf.view-names= # Comma-separated list of view names that can be resolved.
接管Spring Boot的Web配置:
好好读读下面两段话:
如果Spring Boot提供的Spring MVC默认配置不符合你的需求,则可以通过一个配置类(注解有@Configuration)加上@EnableWebMvc注解来实现完全自己控制的MVC配置。这种情况,这种方法不推荐。
当然,在通常情况下,Spring Boot的自动配置是符合我们大多数需求的。在你既需要保留Spring Boot提供的便利,又需要增加自己的额外的配置的时候,可以定义一个配置类并继承WebMvcConfigurerAdapter,无须使用@EnableWebMvc注解。然后按照第4章讲的Spring MVC的配置方法来添加Spring Boot为我们所做的其他配置。
关键点是:可以通过Spring MVC的配置方法来配置Spring Boot。
@Configurationpublic class WebMvcConfig extends WebMvcConfigurerAdapter{@overridepublic void addViewControllers(ViewControllerRegistry registry){ registry.addViewController("/xx").addViewName("xx");}}
值得指出的是:在这里重写的addViewController方法,并不会覆盖WebMvcAutoConfiguration中的addViewControllers(在源码中,默认的有一个配置,Spring Boot将”/”映射到index.html),这也就意味着我们的配置和Spring Boot的自动配置同时有效,这也是我们推荐添加自己的MVC配置的方式。
WebSocket:
WebSocket为浏览器和服务端提供了双工异步通信的功能,即浏览器可以向服务端发送消息,服务端也可以向浏览器发送消息。
WebSocket是通过一个socket来实现双工异步通信能力的。但是直接使用WebSocket协议会显得非常繁琐,我们会使用它的子协议STOMP,它是一个更高级别的协议,STOMP协议使用一个基于帧(frame)的格式来定义信息,与HTTP的request和response类似(具有类似于@RequestMapping的@MessageMapping)。
1.广播式:
广播式即服务端有消息时,会将消息发送给所有连接了当前endpoint的浏览器。
2.点对点式:
广播式有自己的应用场景,但是广播式不能解决我们一个常见的场景,即消息由谁发送,由谁接收的问题。
基于Bootstrap和AngularJS的现代Web应用:
现代的B/S系统有下面几个特色:
1.单页面应用
单页面应用(single-page application,简称SPA)值的是一种类似于原生客户端软件的更流畅的用户体验页面。
在单页面的应用中,所有的资源(HTML,JavaScript,CSS)都是按需动态加载到页面上的,且不需要服务端控制页面的转向。
2.响应式设计
响应式设计(Responsive web design,简称RWD)指的是不同的设备访问相同的页面的时候,得到不同的页面视图,而得到的视图是适应当前屏幕的。
3.数据导向
数据导向是对于页面导向而言的,页面上的数据获得是通过消费后台的REST服务来实现的,而不是通过服务器渲染的动态界面(如JSP)来实现的,一般数据交换使用的格式是JSON。
AngularJS:
HTML一般是用来申明静态页面的,但是通常情况下我们希望页面是基于数据动态生成的,这也是我们很多服务器端模板引擎出现的原因,而AngularJS可以只通过前端技术就实现动态的页面。
@RestController@SpringBootApplicationpublic class Ch77Application { @RequestMapping(value="/search",produces={MediaType.APPLICATION_JSON_VALUE}) public Person search(String personName){ return new Person(personName, 32, "hefei"); } public static void main(String[] args) { SpringApplication.run(Ch77Application.class, args); }}
上面的代码我们模拟一个查询,即接收前台传入的personName,然后返回Person类,因为我们使用的是@RestController,且返回值类型是Person,所以Spring MVC会自动将对象输出为JSON。注意代码中的:
produces={MediaType.APPLICATION_JSON_VALUE}
Chapter8.Spring Boot的数据访问
Spring Data为我们使用统一的API来对很多数据存储技术(比如关系性和非关系型数据库)进行数据访问操作提供了支持。这是Spring通过提供Spring Data Commons项目来实现的,它是上述各种Spring Data项目的依赖。Spring Data Commons让我们在使用关系型或非关系型数据访问技术时都使用基于Spring的统一标准,该标准包含CURD(创建,获取,更新,删除),查询,排序和分页的相关操作。
Spring Data Commons的一个重要概念:Spring Data Repository抽象。使用Spring Data Repository可以极大地减少数据访问层的代码。既然是数据访问操作的统一标准,那肯定是定义了各种各样和数据访问有关的接口,Spring Data Repository抽象的根接口是Repository接口。
public interface Repository<T,ID extends Serializable>{}
子接口CurdRepository定义了和CRUD操作相关的内容:
public interface CurdRepository<T,ID extends Serializable> extends Repository<T,ID>{}
CurdRepository的子接口PagingAndSortingRepository定义了与分页和排序操作相关的内容:
public interface PagingAndSortingRepository<T,ID extends Serializable> extends CurdRepository<T,ID>{}
Docker:
Docker是一个轻量级容器技术,类似于虚拟机技术。Docker是直接运行在当前操作系统(Linux)上,而不是运行在虚拟机中,但也实现了虚拟机技术的资源隔离,性能远远高于虚拟机技术。
Docker支持将软件编译成一个镜像(image),在这个镜像里做好对软件的各种配置,然后发布这个镜像,使用者可以运行这个镜像,运行中的镜像称之为容器(container),容器的启动是非常快的,一般以秒为单位。举例来说,有点像我们平时安装的ghost系统,系统安装后软件都有了,虽然完全不是一种东西,但是思路是类似的。
需要指出的是,Docker并不是为开发测试方便而提供的小工具,而是可以用于实际生产环境的一种极好的部署方式。
Spring Data提供了一个初始化数据的功能:放置在类路径下的schema.sql文件会自动用来初始化表结构;放置在类路径下的data.sql文件会自动用来填充数据。
定义映射实体类:
Hibernate支持自动将实体类映射为数据表格:
@Entity //1@NamedQuery(name = "Person.withNameAndAddressNamedQuery",query = "select p from Person p where p.name=?1 and address=?2")public class Person { @Id //2 @GeneratedValue //3 private Long id; private String name; private Integer age; private String address; public Person() { super(); } public Person(Long id, String name, Integer age, String address) { super(); this.id = id; this.name = name; this.age = age; this.address = address; }}
解释:
@Entity注解指明这是一个和数据库表映射的实体类
@Id注解指明这个属性映射为数据库的主键
@GeneratedValue注解默认使用主键生成方式为自增,hibernate会为我们自动生成一个名为HIBERNATE_SEQUENCE的序列
在此例中,使用的注解也许和平时使用的注解实体类不大一样,比如没有使用@Table(实体类映射表名),@Column(属性映射字段名)注解。这是因为我们采用的是正向工程通过实体类生成表结构,而不是通过逆向工程从表结构生成数据库。
Spring的事务机制:
所有的数据访问技术都有事务处理机制,这些技术提供了API用来开启事务,提交事务来完成数据操作,或者在发生错误的时候回滚数据。
Spring的事务机制是用统一的机制来处理不同数据访问技术的事务处理。Spring的事务机制提供了一个PlatformTransactionManager接口,不同的数据访问技术的事务使用不同的接口实现:
1.JDBC:DataSourceTransactionManager
2.JPA:JpaTransactionManager
3.Hibernate:HibernateTransactionManager
4.JDO:JdoTransactionManager
5.分布式事务:JtaTransactionManager
数据缓存Cache:
一个程序的瓶颈在于数据库,内存的速度是远远大于硬盘的。
Spring支持的CacheManager:
1.SimpleCacheManager:使用简单的Collection来存储缓存,主要用来测试用途
2.EhCacheManager:使用EhCache作为缓存技术
3.RedisCacheManager:使用Redis作为缓存技术
//@CachePut缓存新增或者更新的数据到缓存,其中缓存名为people,数据的key是person的id@CachePut(value="people",key="#person.id")public Person save(Person person){} //@CacheEvict从缓存people中删除key为id的数据@CacheEvict(value="people")public void remove(Long id){}
弄清@Caching,@Cacheable,@CachePut,@CacheEvict等其他更多缓存注解的概念。
Redis:
Redis是一个基于键值对的开源内存数据存储,当然Redis也可以做数据缓存。
更多文档可移步Spring Data Redis官方文档。
示例:
1.实体类:
public class Person implements Serializable{ private static final long serialVersionUID = 1L; private String id; private String name; private Integer age; public Person() { super(); } public Person(String id,String name, Integer age) { super(); this.id = id; this.name = name; this.age = age; }}
必须用时间序列化接口,因为使用Jackson做序列化需要一个空构造。
2.数据访问:
@Repositorypublic class PersonDao { @Autowired StringRedisTemplate stringRedisTemplate; //1 @Resource(name="stringRedisTemplate") ValueOperations<String,String> valOpsStr; //3 @Autowired RedisTemplate<Object, Object> redisTemplate; //2 @Resource(name="redisTemplate") ValueOperations<Object, Object> valOps; //4 public void stringRedisTemplateDemo(){ //5 valOpsStr.set("xx", "yy"); } public void save(Person person){ //6 valOps.set(person.getId(),person); } public String getString(){//7 return valOpsStr.get("xx"); } public Person getPerson(){//8 return (Person) valOps.get("1"); }}
Spring Boot为我们自动配置了RedisTemplate,而RedisTemplate使用的是JdkSerializationRedisSerializer,这个对我们演示Reids Client很不直观,因为JdkSerializationRedisSerializer使用二进制形式存储数据,在此我们将自己配置RedisTemplate并定义Serializer。
3.自定义:
@SpringBootApplicationpublic class Ch862Application { public static void main(String[] args) { SpringApplication.run(Ch862Application.class, args); } //自定义 @Bean @SuppressWarnings({ "rawtypes", "unchecked" }) public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>(); template.setConnectionFactory(redisConnectionFactory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setValueSerializer(jackson2JsonRedisSerializer); //1设置value的序列化采用 //Jackson2JsonRedisSerializer template.setKeySerializer(new StringRedisSerializer()); //2设置key的序列化采用 //StringRedisSerializer template.afterPropertiesSet(); return template; }}
4.控制器:
@RestControllerpublic class DataController { @Autowired PersonDao personDao; @RequestMapping("/set") //1 public void set(){ Person person = new Person("1","wyf", 32); personDao.save(person); personDao.stringRedisTemplateDemo(); } @RequestMapping("/getStr") //2 public String getStr(){ return personDao.getString(); } @RequestMapping("/getPerson") //3 public Person getPerson(){ return personDao.getPerson(); }}
Chapter9.企业级开发
Spring Security:
配置:
@configuration@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigureAdapter{}
安全框架的两个重要概念:1.认证(authentication)和2.授权(authorization)。认证即确认用户可以访问当前系统;授权即确定用户在当前系统下所拥有的功能权限。
用户认证:
认证需要我们有一套用户数据的来源,而授权则是对于某个用户有相应的角色权限。在Spring Security中我们通过重写
protected void configure(AutheticationManagerBuilder auth)
来实现。
分为三种:
1.内存中的用户
2.JDBC中的用户
3.通用的用户
请求授权:
在Spring Security中我们通过重写
protected void configure(HttpSecurity http)
来实现请求拦截的。
Spring Security使用下面匹配器来匹配请求路径:
1.antMachers:使用Ant风格的路径匹配
2.regexMachers:使用正则表达式匹配
3.anyRequest:匹配所有请求路径
示例:
@overrideprotected void configure(HttpSecurity http)throws Exception{http.authorizeRequests()//1开始请求权限配置.antMatchers("/admin/**").hasRole("ROLE_ADMIN")//2.antMatchers("/user/**").hasRole("ROLE_ADMIN","ROLE_USER")//3.anyRequest().authenticated();//4其余所有的请求都需要认证(登陆后)才可访问}
Spring Boot的测试:
//主类@SpringBootApplicationpublic class Ch104Application { public static void main(String[] args) { SpringApplication.run(Ch104Application.class, args); }}//测试类@RunWith(SpringJUnit4ClassRunner.class)//使用@SpringApplicationConfiguration代替//@ContextConfiguration来配置//Spring Boot的Application Context@SpringApplicationConfiguration(classes = Ch104Application.class) @WebAppConfiguration@Transactional //2public class Ch104ApplicationTests { @Autowired PersonRepository personRepository; MockMvc mvc; @Autowired WebApplicationContext webApplicationContext; String expectedJson; @Before //3 public void setUp() throws JsonProcessingException{ Person p1 = new Person("wyf"); Person p2 = new Person("wisely"); personRepository.save(p1); personRepository.save(p2); expectedJson =Obj2Json(personRepository.findAll()); //4 mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); } protected String Obj2Json(Object obj) throws JsonProcessingException{//5 ObjectMapper mapper = new ObjectMapper(); return mapper.writeValueAsString(obj); } @Test public void testPersonController() throws Exception { String uri="/person"; MvcResult result = mvc.perform(MockMvcRequestBuilders.get(uri).accept(MediaType.APPLICATION_JSON)) .andReturn(); //6 int status = result.getResponse().getStatus(); //7 String content = result.getResponse().getContentAsString(); //8 Assert.assertEquals("错误,正确的返回值为200",200, status); //9 Assert.assertEquals("错误,返回值和预期返回值不一致", expectedJson,content); //10 }}
Chapter10.Spring Boot开发部署与测试
部署形式:
1.jar形式
注册为Linux服务:
Linux下运行的软件我们通常把它注册为服务,这样我们就可以通过命令开启,关闭以及保持开机启动等功能。
将jar注册为服务(在CentOS上):
//其中zeng就是我们服务名sudo ln -s /dir/zeng-1-0.jar /etc/init.d/zeng
启动服务:
service zeng start
停止服务:
service zeng stop
服务状态:
service zeng status
开机启动:
chkconfig zeng on
The End!
- spring boot实战一
- Spring Boot实战
- spring boot实战笔记
- [Spring Boot实战系列]
- Spring Boot 实战(一)
- Spring Boot实战笔记
- Spring Boot实战
- [Spring Boot实战系列]
- Spring Boot实战pdf
- Spring Boot实战 目录
- 《Spring Boot 实战》-- 读书笔记
- spring-boot实战:shiro
- Spring Boot功能实战
- spring boot实战目录
- [Spring Boot实战系列]
- [Spring Boot实战系列]
- Spring Boot实战之入门
- Spring Boot实战之单元测试
- 2016.11.9
- C++笔记——运算符重载
- css expression
- WebStorm For Mac下载及破解方法
- Android 倒计时按钮的实现
- Spring Boot实战
- 类内CONST
- String、StringBuffer与StringBuilder详解
- 安卓异常捕获
- 负载均衡之权重轮询调度算法
- MSVC 工程属性设置
- 关于glib的一些知识记录
- Parajumpers Herre is small wasteful to
- 2016ccpc合肥赛区 1005扫雷