使用Spring Boot和Gradle创建AngularJS项目
Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
本文主要是记录使用 Spring Boot 和 Gradle 创建项目的过程,其中会包括 Spring Boot 的安装及使用方法,希望通过这篇文章能够快速搭建一个项目。
1. 开发环境 操作系统: mac JDK:1.7.0_60 Gradle:2.2.1 IDE:Idea 2. 创建项目你可以通过 Spring Initializr 来创建一个空的项目,也可以手动创建,这里我使用的是手动创建 gradle 项目。
参考 使用Gradle构建项目 创建一个 ng-spring-boot 项目,执行的命令如下:
$ mkdir ng-spring-boot cd ng-spring-boot $ gradle init
ng-spring-boot 目录结构如下:
ng-spring-boot tree ├── build.gradle ├── gradle │ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle 2 directories, 6 files
然后修改 build.gradle 文件:
buildscript { ext { springBootVersion = 1.2.2.RELEASE repositories { mavenCentral() dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") apply plugin: java apply plugin: eclipse apply plugin: idea apply plugin: spring-boot jar { baseName = ng-spring-boot version = 0.0.1-SNAPSHOT sourceCompatibility = 1.7 targetCompatibility = 1.7 repositories { mavenCentral() maven { url "https://repo.spring.io/libs-release" } dependencies { compile("org.springframework.boot:spring-boot-starter-data-jpa") compile("org.springframework.boot:spring-boot-starter-web") compile("org.springframework.boot:spring-boot-starter-actuator") runtime("org.hsqldb:hsqldb") testCompile("org.springframework.boot:spring-boot-starter-test") eclipse { classpath { containers.remove(org.eclipse.jdt.launching.JRE_CONTAINER) containers org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7 task wrapper(type: Wrapper) { gradleVersion = 2.3
使用 spring-boot-gradle-plugin 插件可以提供一些创建可执行 jar 和从源码运行项目的任务,它还提供了 ResolutionStrategy 以方便依赖中不用写版本号。
3. 创建一个可执行的类首先,新建一个符合 Maven 规范的目录结构:
$ mkdir -p src/main/java/com/javachen
创建一个 Sping boot 启动类:
package com.javachen; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @EnableAutoConfiguration @ComponentScan public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args);
main 方法使用了 SpringApplication 工具类。这将告诉Spring去读取 Application 的元信息,并在Spring的应用上下文作为一个组件被管理。
@Configuration 注解告诉 spring 该类定义了 application context 的 bean 的一些配置。
@ComponentScan 注解告诉 Spring 遍历带有 @Component 注解的类。这将保证 Spring 能找到并注册 GreetingController,因为它被 @RestController 标记,这也是 @Component 的一种。
@EnableAutoConfiguration 注解会基于你的类加载路径的内容切换合理的默认行为。比如,因为应用要依赖内嵌版本的 tomcat,所以一个tomcat服务器会被启动并代替你进行合理的配置。再比如,因为应用要依赖 Spring 的 MVC 框架,一个 Spring MVC 的 DispatcherServlet 将被配置并注册,并且不再需要 web.xml 文件。
上面三个注解还可以用 @SpringBootApplication 代替:
package com.javachen.examples.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args);
你也可以修改该类的 main 方法,获取 ApplicationContext:
package com.javachen; import java.util.Arrays; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @SpringBootApplication public class Application { public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(Application.class, args); System.out.println("Lets inspect the beans provided by Spring Boot:"); String[] beanNames = ctx.getBeanDefinitionNames(); Arrays.sort(beanNames); for (String beanName : beanNames) { System.out.println(beanName);4. 创建一个实体类
创建一个实体类 src/main/java/com/javachen/model/Item.java:
package com.javachen.model; import javax.persistence.*;创建一个 Restfull 的控制类,该类主要提供增删改查的方法:
package com.javachen.controller; import com.javachen.model.Item; import com.javachen.repository.ItemRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import javax.persistence.EntityNotFoundException; import java.util.List; @RestController @RequestMapping("/items") public class ItemController { @Autowired private ItemRepository repo; @RequestMapping(method = RequestMethod.GET) public List Item findItems() { return repo.findAll(); @RequestMapping(method = RequestMethod.POST) public Item addItem(@RequestBody Item item) { item.setId(null); return repo.saveAndFlush(item); @RequestMapping(value = "/{id}", method = RequestMethod.PUT) public Item updateItem(@RequestBody Item updatedItem, @PathVariable Integer id) { Item item = repo.getOne(id); item.setChecked(updatedItem.isChecked()); item.setDescription(updatedItem.getDescription()); return repo.saveAndFlush(item); @RequestMapping(value = "/{id}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.NO_CONTENT) public void deleteItem(@PathVariable Integer id) { repo.delete(id); @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(value = { EmptyResultDataAccessException.class, EntityNotFoundException.class }) public void handleNotFound() { }Greeting 对象会被转换成 JSON 字符串,这得益于 Spring 的 HTTP 消息转换支持,你不必人工处理。由于 Jackson2 在 classpath 里,Spring的MappingJackson2HttpMessageConverter 会自动完成这一工作。
这段代码使用 Spring4 新的注解:@RestController,表明该类的每个方法返回对象而不是视图。它实际就是 @Controller 和 @ResponseBody 混合使用的简写方法。
6. 创建 JPA 仓库使用 JAP 来持久化数据:
package com.javachen.repository; import com.javachen.model.Item; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import java.util.List; public interface ItemRepository extends JpaRepository Item, Integer { @Query("SELECT i FROM Item i WHERE i.checked=true") List Item findChecked();Spring Boot 可以自动配置嵌入式的数据库,包括 H2、HSQL 和 Derby,你不需要配置数据库链接的 url,只需要添加相关的依赖即可。另外,你还需要依赖 spring-jdbc,在本例中,我们是引入了对 spring-boot-starter-data-jpa 的依赖。如果你想使用其他类型的数据库,则需要配置 spring.datasource.* 属性,一个示例是在 application.properties 中配置如下属性:
spring.datasource.url=jdbc:mysql://localhost/test spring.datasource.username=dbuser spring.datasource.password=dbpass spring.datasource.driver-class-name=com.mysql.jdbc.Driver创建 src/main/resources/application.properties 文件,修改 JPA 相关配置,如:
spring.jpa.hibernate.ddl-auto=create-drop注意:
SpringApplication 会在以下路径查找 application.properties 并加载该文件:
/config 目录下 classpath 中 /config 包下 classpath 根路径下可以在项目根路径直接运行下面命令:
$ export JAVA_OPTS=-Xmx1024m -XX:MaxPermSize=128M -Djava.security.egd=file:/dev/./urandom $ ./gradlew bootRun也可以先 build 生成一个 jar 文件,然后执行该 jar 文件:
$ ./gradlew build java -jar build/libs/ng-spring-boot-0.0.1-SNAPSHOT.jar启动过程中你会看到如下内容,这部分内容是在 Application 类中打印出来的:
Lets inspect the beans provided by Spring Boot: application beanNameHandlerMapping defaultServletHandlerMapping dispatcherServlet embeddedServletContainerCustomizerBeanPostProcessor handlerExceptionResolver helloController httpRequestHandlerAdapter messageSource mvcContentNegotiationManager mvcConversionService mvcValidator org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration$DispatcherServletConfiguration org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration$EmbeddedTomcat org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration org.springframework.boot.context.embedded.properties.ServerProperties org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration propertySourcesBinder propertySourcesPlaceholderConfigurer requestMappingHandlerAdapter requestMappingHandlerMapping resourceHandlerMapping simpleControllerHandlerAdapter tomcatEmbeddedServletContainerFactory viewControllerHandlerMapping你也可以启动远程调试:
$ ./gradlew build $ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \ -jar build/libs/spring-boot-examples-0.0.1-SNAPSHOT.jar接下来,打开浏览器访问 http://localhost:8080/items,你会看到页面输出一个空的数组。然后,你可以使用浏览器的 Restfull 插件来添加、删除、修改数据。
8. 添加前端库文件这里主要使用 Bower 来管理前端依赖,包括 angular 和 bootstrap。
配置 Bower ,需要在项目根目录下创建 .bowerrc 和 bower.json 两个文件。
.bowerrc 文件制定下载的依赖存放路径:
{ "directory": "src/main/resources/static/bower_components", "json": "bower.json"bower.json 文件定义依赖关系:
{ "name": "ng-spring-boot", "dependencies": { "angular": "~1.3.0", "angular-resource": "~1.3.0", "bootstrap-css-only": "~3.2.0"如果你没有安装 Bower,则运行下面命令进行安装:
npm install -g bower安装之后下载依赖:
bower install运行成功之后,查看 src/main/resources/static/bower_components 目录结构:
src/main/resources/static/bower_components ├── angular ├── angular-resource └── bootstrap-css-only我们可以将bower_components目录改名为lib,同时修改.bowerrc文件如下:
{ "directory": "src/main/resources/static/libs", "json": "bower.json"9. 创建前端页面注意:
前端页面和 js 存放到 public 目录下,是因为 Spring Boot 会自动在 /static 或者 /public 或者 /resources 或者 /META-INF/resources 加载静态页面。
创建 index.html创建 public 目录存放静态页面 index.html:
!DOCTYPE html html lang="en" head link rel="stylesheet" href="./lib/bootstrap-css-only/css/bootstrap.min.css" / /head body ng-app="myApp" div ng-controller="AppController" div h1 A checklist /h1 /div div role="alert" ng-hide="items amp; amp; items.length 0" There are no items yet. /div form role="form" ng-submit="addItem(newItem)" div ng-repeat="item in items" div label input type="checkbox" ng-model="item.checked" ng-change="updateItem(item)"/ /label /div div button type="button" title="Delete" ng-click="deleteItem(item)" span /span /button /div /div hr / div input type="text" ng-model="newItem" placeholder="Enter the description..." / span button type="submit" ng-disabled="!newItem" title="Add" span /span /button /span /div /form /div script type="text/javascript" src="./lib/angular/angular.min.js" /script script type="text/javascript" src="./lib/angular-resource/angular-resource.min.js" /script script type="text/javascript" src="./lib/lodash/dist/lodash.min.js" /script script type="text/javascript" src="./app/app.js" /script script type="text/javascript" src="./app/controllers.js" /script script type="text/javascript" src="./app/services.js" /script /body /html初始化 AngularJS这里使用闭包的方式来初始化 AngularJS,代码见 public/app/app.js :
(function(angular) { angular.module("myApp.controllers", []); angular.module("myApp.services", []); angular.module("myApp", ["ngResource", "myApp.controllers", "myApp.services"]); }(angular));创建 resource factory代码见 public/app/services.js :
(function(angular) { var ItemFactory = function($resource) { return $resource(/items/:id, { id: @id }, { update: { method: "PUT" remove: { method: "DELETE" ItemFactory.$inject = [$resource]; angular.module("myApp.services").factory("Item", ItemFactory); }(angular));创建控制器代码见 public/app/controllers.js :
(function(angular) { var AppController = function($scope, Item) { Item.query(function(response) { $scope.items = response ? response : []; $scope.addItem = function(description) { new Item({ description: description, checked: false }).$save(function(item) { $scope.items.push(item); $scope.newItem = ""; $scope.updateItem = function(item) { item.$update(); $scope.deleteItem = function(item) { item.$remove(function() { $scope.items.splice($scope.items.indexOf(item), 1); AppController.$inject = [$scope, Item]; angular.module("myApp.controllers").controller("AppController", AppController); }(angular));10. 测试前端页面再一次打开浏览器,访问 http://localhost:8080/ 进行测试。
11. 前后端分离部署
对于AngularJS应用,我们可以使用nodejs或者其他容器部署应用,例如,这里可以使用groovy服务来启动前端服务,然后通过http请求调用后端服务的接口。
先创建app.groovy文件:
@Controller class JsApp { }修改services.js文件中的请求地址为 http://localhost:8080/items/:id:
(function(angular) { var ItemFactory = function($resource) { return $resource(http://localhost:8080/items/:id, { id: @id }, { update: { method: "PUT" remove: { method: "DELETE" ItemFactory.$inject = [$resource]; angular.module("myApp.services").factory("Item", ItemFactory); }(angular));然后,启动groovy服务来托管静态文件,这里使用9000端口:
spring run app.groovy -- --server.port=9000这时候,就可以服务 http://localhost:9000/ 来查看前端页面了。
这样,前后端就是分别部署属于两个不同的应用了,为了解决跨域的问题,需要添加一个过滤器,如下:
package com.javachen.filter; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class SimpleCORSFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); chain.doFilter(req, res); public void init(FilterConfig filterConfig) {} public void destroy() {}然后,重启应用就可以了。
12. 总结本文主要是记录快速使用 Spring Boot 和 Gradle 创建 AngularJS 项目的过程,并介绍了如何将前后端进行分离和解决跨域访问的问题,希望能对你有所帮助。
文中相关的源码在 ng-spring-boot,你可以下载该项目,然后编译、运行代码。
Spring boot 使用 ON DUPLICATE KEY UPDATE属性控制版本 更新数据不成功 如果更新不成功会报下面的错误(此错误是自定义的): The data you want to update has been updated by another user. Please reopen and try again! 一、主要按下面的流程检查: 1、检查数据库的段alastupdatetime定义 2、检查.xml的alastupdatetime 3、要更新数据的主键是否在同一个updateByBatch中的List中重复出现
雨客 微博@JavaChen,这里的所有博客文章来自http://blog.javachen.com/。
阿里特邀专家徐雷Java Spring Boot开发实战系列课程(第18讲):制作Java Docker镜像与推送到DockerHub和阿里云Docker仓库 立即下载
相关文章
- spring 之 init-method & InitializingBean
- 【Spring Boot】Spring Boot之两种引入spring boot maven依赖的方式
- spring boot mybatis 整合教程
- Spring Boot 2.x :通过 spring-boot-starter-hbase 集成 HBase
- [Spring Boot] Introduce to Mockito
- spring boot:构建多模块项目(spring boot 2.3.1)
- spring boot:实现图片文件上传并生成缩略图(spring boot 2.3.1)
- 基于Gradle的spring boot 项目构建
- Spring Boot(一):快速开始
- CQRS模式应用Spring Boot+Scala框架集成开发
- 深入理解Spring Redis的使用 (一)、Spring Redis基本使用
- Spring Boot——2分钟构建spring web mvc REST风格HelloWorld
- spring boot:swagger3的安全配置(swagger 3.0.0 / spring security / spring boot 2.3.3)
- Spring实战2:装配bean—依赖注入的本质
- Spring标签之Bean @Scope
- 学习Spring Boot:(一)入门
- Spring Boot 架构中的国际化支持实践—— Spring Boot 全球化解决方案
- 解决com.alibaba.fastjson.JSONException: write javaBean error问题以及解决Spring Boot加入Shiro导致spring aop失效的问题
- java ee wildfly spring 在线程池的线程中注入
- Spring整合Bean Validation
- Spring MVC中@Controller和@RequestMapping注解详解
- 【java】Spring Boot -- Spring AOP原理及简单实现