Mkyong-中文博客翻译-七-

news/2025/1/12 22:56:00/文章来源:https://www.cnblogs.com/apachecn/p/18520577

Mkyong 中文博客翻译(七)

原文:Mkyong

协议:CC BY-NC-SA 4.0

Spring 3 JavaConfig @Import 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-3-javaconfig-import-example/

通常,您会将一个大的 Spring XML bean 文件分割成多个小文件,按模块或类别分组,以使事情更易于维护和模块化。举个例子,

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><import resource="config/customer.xml"/><import resource="config/scheduler.xml"/></beans> 

在 Spring3 JavaConfig 中,等效的功能是 @Import

 package com.mkyong.config;import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;@Configuration
@Import({ CustomerConfig.class, SchedulerConfig.class })
public class AppConfig {} 

@导入示例

查看使用 JavaConfig @Import 的完整示例。

1.目录结构

这个例子的目录结构。

directory structure of this example ## 2.春豆

两个简单的春豆。

文件:CustomerBo.java

 package com.mkyong.core;public class CustomerBo {public void printMsg(String msg) {System.out.println("CustomerBo : " + msg);}} 

文件:SchedulerBo.java

 package com.mkyong.core;public class SchedulerBo {public void printMsg(String msg) {System.out.println("SchedulerBo : " + msg);}} 

3.@配置示例

现在,使用 JavaConfig**@ Configuration**来声明上面的 beans。

文件:CustomerConfig.java

 package com.mkyong.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import com.mkyong.core.CustomerBo;@Configuration
public class CustomerConfig {@Bean(name="customer")public CustomerBo customerBo(){return new CustomerBo();}
} 

文件:SchedulerConfig.java

 package com.mkyong.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.mkyong.core.SchedulerBo;@Configuration
public class SchedulerConfig {@Bean(name="scheduler")public SchedulerBo suchedulerBo(){return new SchedulerBo();}} 

4.@导入示例

使用 @Import 加载多个配置文件。

文件:AppConfig.java

 package com.mkyong.config;import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;@Configuration
@Import({ CustomerConfig.class, SchedulerConfig.class })
public class AppConfig {} 

5.运行它

加载主配置文件,并测试它。

 package com.mkyong.core;import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.mkyong.config.AppConfig;public class App {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);CustomerBo customer = (CustomerBo) context.getBean("customer");customer.printMsg("Hello 1");SchedulerBo scheduler = (SchedulerBo) context.getBean("scheduler");scheduler.printMsg("Hello 2");}
} 

输出

 CustomerBo : Hello 1
SchedulerBo : Hello 2 

下载源代码

Download It – Spring3-JavaConfig-Import-Example.zip (7 KB)

参考

  1. spring 3 @配置示例
  2. Spring XML 导入示例

javaconfig spring3

Spring 3 MVC 和 JSON 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-3-mvc-and-json-example/

在本教程中,我们将向您展示如何在 Spring MVC 框架中输出 JSON 数据。

使用的技术:

  1. 弹簧 3.2.2 释放
  2. 杰克逊 1.9.10
  3. JDK 1.6
  4. Eclipse 3.6
  5. maven3

在 Spring 3 中,要输出 JSON 数据,只需将 Jackson 库放在项目类路径中。

1.项目相关性

获得杰克逊和春天的依赖。

pom.xml

 <project  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong.common</groupId><artifactId>SpringMVC</artifactId><packaging>war</packaging><version>1.0-SNAPSHOT</version><name>SpringMVC Json Webapp</name><url>http://maven.apache.org</url><properties><spring.version>3.2.2.RELEASE</spring.version><jackson.version>1.9.10</jackson.version><jdk.version>1.6</jdk.version></properties><dependencies><!-- Spring 3 dependencies --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!-- Jackson JSON Mapper --><dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-mapper-asl</artifactId><version>${jackson.version}</version></dependency></dependencies><build><finalName>SpringMVC</finalName><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-eclipse-plugin</artifactId><version>2.9</version><configuration><downloadSources>true</downloadSources><downloadJavadocs>false</downloadJavadocs><wtpversion>2.0</wtpversion></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>${jdk.version}</source><target>${jdk.version}</target></configuration></plugin></plugins></build></project> 

2.模型

一个简单的 POJO,稍后将这个对象输出为格式化的 JSON 数据。

 package com.mkyong.common.model;public class Shop {String name;String staffName[];//getter and setter methods} 

3.控制器

添加@ResponseBody作为返回值。闻春见

  1. 项目类路径中存在 Jackson 库
  2. mvc:annotation-driven被启用
  3. 用@ResponseBody 批注的返回方法

Spring 会自动处理 JSON 转换。

JSONController.java

 package com.mkyong.common.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.mkyong.common.model.Shop;@Controller
@RequestMapping("/kfc/brands")
public class JSONController {@RequestMapping(value="{name}", method = RequestMethod.GET)public @ResponseBody Shop getShopInJSON(@PathVariable String name) {Shop shop = new Shop();shop.setName(name);shop.setStaffName(new String[]{"mkyong1", "mkyong2"});return shop;}} 

4.mvc:注释驱动

在 Spring 配置 XML 文件中启用mvc:annotation-driven

mvc-dispatcher-servlet.xml

 <beans xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"><context:component-scan base-package="com.mkyong.common.controller" /><mvc:annotation-driven /></beans> 

5.演示

网址:http://localhost:8080/spring MVC/rest/KFC/brands/KFC-kampar

spring mvc and json demo

下载源代码

Download it – SpringMVC-Json-Example.zip (21 KB)

参考

  1. mvc 注释驱动的文档
  2. 高性能 JSON 处理器
  3. Spring MVC 和 XML 示例

Spring 3 MVC 和 JSR303 @Valid 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-3-mvc-and-jsr303-valid-example/

在 Spring 3 中,你可以启用“ mvc:注释驱动的”来支持 JSR303 bean 验证通过@Valid注释,如果类路径上有任何 JSR303 验证器框架的话。

Note
Hibernate Validator is the reference implementation for JSR 303

在本教程中,我们将向您展示如何通过@Valid注释将 Hibernate validator 与 Spring MVC 集成在一起,以在 HTML 表单中执行 bean 验证。

使用的技术:

  1. 弹簧 3.0.5 释放
  2. Hibernate 验证程序 4.2.0 .最终版
  3. JDK 1.6
  4. Eclipse 3.6
  5. maven3

1.项目相关性

Hibernate 验证器可以在 JBoss 公共存储库中获得。

 <repositories><repository><id>JBoss repository</id><url>http://repository.jboss.org/nexus/content/groups/public/</url></repository></repositories><properties><spring.version>3.0.5.RELEASE</spring.version></properties><dependencies><!-- Spring 3 dependencies --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!-- Hibernate Validator --><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>4.2.0.Final</version></dependency></dependencies> 

2.JSR303 Bean 验证

一个简单的 POJO,用 Hibernate validator 注释进行了注释。

Note
Refer to this Hibernate validator documentation for detail explanation

 package com.mkyong.common.model;import org.hibernate.validator.constraints.NotEmpty;
import org.hibernate.validator.constraints.Range;public class Customer {@NotEmpty //make sure name is not emptyString name;@Range(min = 1, max = 150) //age need between 1 and 150int age;//getter and setter methods} 

3.控制器+@有效

为了验证工作,只需通过@Valid对“JSR 注释模型对象”进行注释。仅此而已,其他东西只是普通的 Spring MVC 表单处理。

 package com.mkyong.common.controller;import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.mkyong.common.model.Customer;@Controller
@RequestMapping("/customer")
public class SignUpController {@RequestMapping(value = "/signup", method = RequestMethod.POST)public String addCustomer(@Valid Customer customer, BindingResult result) {if (result.hasErrors()) {return "SignUpForm";} else {return "Done";}}@RequestMapping(method = RequestMethod.GET)public String displayCustomerForm(ModelMap model) {model.addAttribute("customer", new Customer());return "SignUpForm";}} 

4.出错信息

默认情况下,如果验证失败。

  1. @NotEmpty将显示"不得为空"
  2. @Range将显示“必须在 1 和 150 之间”

您可以很容易地覆盖它,用“key”和 message 创建一个属性。要知道哪个@注释绑定到哪个键,只需调试它并查看“BindingResult result”中值。正常情况下,key 为“@ Annotation name . object . field name”。

文件:messages.properties

 NotEmpty.customer.name = Name is required!
Range.customer.age = Age value must be between 1 and 150 

5.mvc:注释驱动

启用“mvc:annotation-driven”使 Spring MVC 通过@Valid支持 JSR303 验证器,同时绑定你的属性文件。

 <beans xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"><context:component-scan base-package="com.mkyong.common.controller" /><!-- support JSR303 annotation if JSR 303 validation present on classpath --><mvc:annotation-driven /><bean id="viewResolver"class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix"><value>/WEB-INF/pages/</value></property><property name="suffix"><value>.jsp</value></property></bean><!-- bind your messages.properties --><bean class="org.springframework.context.support.ResourceBundleMessageSource"id="messageSource"><property name="basename" value="messages" /></bean></beans> 

6.JSP 页面

最后一个,带 Spring 表单标签库的普通 JSP 页面。

文件:sign form . JSP

 <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<style>
.error {color: #ff0000;
}.errorblock {color: #000;background-color: #ffEEEE;border: 3px solid #ff0000;padding: 8px;margin: 16px;
}
</style>
</head><body><h2>Customer SignUp Form - JSR303 @Valid example</h2><form:form method="POST" commandName="customer" action="customer/signup"><form:errors path="*" cssClass="errorblock" element="div" /><table><tr><td>Customer Name :</td><td><form:input path="name" /></td><td><form:errors path="name" cssClass="error" /></td></tr><tr><td>Customer Age :</td><td><form:input path="age" /></td><td><form:errors path="age" cssClass="error" /></td></tr><tr><td colspan="3"><input type="submit" /></td></tr></table></form:form></body>
</html> 

文件:Done.jsp

 <html>
<body><h2>Done</h2>
</body>
</html> 

6.演示

URL:http://localhost:8080/spring MVC/Customer–客户表单页面,有 2 个文本框用于输入姓名和年龄。

Spring MVC JSR303 demo page

URL:http://localhost:8080/spring MVC/customer/sign up–如果您没有填写表单并单击“提交”按钮,将显示您定制的验证错误消息。

Spring MVC JSR303 demo page - error message

下载源代码

Download it – SpringMVC-Bean-Validation-JSR303-Example-2.zip (9 KB)

参考

  1. Spring JSR303 验证文档
  2. JSR303 bean 验证
  3. 休眠验证器

Tags : spring mvc spring3 validation

Spring 3 MVC 和 RSS 提要示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-3-mvc-and-rss-feed-example/

在 Spring 3 中,附带了一个抽象类" AbstractRssFeedView "来生成 RSS 提要视图,使用 java.net 的 ROME 包。在本教程中,我们将向您展示如何从 Spring MVC 框架中生成 RSS 提要视图。

使用的技术:

  1. 弹簧 3.0.5 释放
  2. 罗马 1.0.0
  3. JDK 1.6
  4. Eclipse 3.6
  5. maven3

在本教程的最后,当你访问这个 URL-http://localhost:8080/spring MVC/rest/rssfeed时,浏览器将返回以下 RSS feed 内容:

 <?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"><channel><title>Mkyong Dot Com</title><link>http://www.mkyong.com</link><description>Java Tutorials and Examples</description><item><title>Spring MVC Tutorial 1</title><link>http://www.mkyong.com/spring-mvc/tutorial-1</link><content:encoded>Tutorial 1 summary ...</content:encoded><pubDate>Tue, 26 Jul 2011 02:26:08 GMT</pubDate></item><item><title>Spring MVC Tutorial 2</title><link>http://www.mkyong.com/spring-mvc/tutorial-2</link><content:encoded>Tutorial 2 summary ...</content:encoded><pubDate>Tue, 26 Jul 2011 02:26:08 GMT</pubDate></item></channel>
</rss> 

1.目录结构

审查最终的项目结构。

directory structure ## 2.项目相关性

对于 Maven,在您的pom.xml中声明以下依赖项。

 <properties><spring.version>3.0.5.RELEASE</spring.version></properties><dependencies><!-- Spring 3 dependencies --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!-- RSS --><dependency><groupId>net.java.dev.rome</groupId><artifactId>rome</artifactId><version>1.0.0</version></dependency><!-- for compile only, your container should have this --><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope></dependency></dependencies> 

3.模型

一个简单的 POJO,稍后使用这个对象来生成 RSS 提要内容。

 package com.mkyong.common.model;import java.util.Date;public class SampleContent {String title;String url;String summary;Date createdDate;//getter and seeter methods
} 

4.摘要提要视图

创建一个类扩展 AbstractRssFeedView ,并覆盖buildFeedMetadatabuildFeedItems方法,下面的代码应该是不言自明的。

 package com.mkyong.common.rss;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.view.feed.AbstractRssFeedView;
import com.mkyong.common.model.SampleContent;
import com.sun.syndication.feed.rss.Channel;
import com.sun.syndication.feed.rss.Content;
import com.sun.syndication.feed.rss.Item;public class CustomRssViewer extends AbstractRssFeedView {@Overrideprotected void buildFeedMetadata(Map<String, Object> model, Channel feed,HttpServletRequest request) {feed.setTitle("Mkyong Dot Com");feed.setDescription("Java Tutorials and Examples");feed.setLink("http://www.mkyong.com");super.buildFeedMetadata(model, feed, request);}@Overrideprotected List<Item> buildFeedItems(Map<String, Object> model,HttpServletRequest request, HttpServletResponse response)throws Exception {@SuppressWarnings("unchecked")List<SampleContent> listContent = (List<SampleContent>) model.get("feedContent");List<Item> items = new ArrayList<Item>(listContent.size());for(SampleContent tempContent : listContent ){Item item = new Item();Content content = new Content();content.setValue(tempContent.getSummary());item.setContent(content);item.setTitle(tempContent.getTitle());item.setLink(tempContent.getUrl());item.setPubDate(tempContent.getCreatedDate());items.add(item);}return items;}} 

5.控制器

Spring MVC 控制器类,生成 rss feed 内容,并返回一个视图名" rssViewer "(这个视图名是属于上面的" CustomRssViewer ",将在后面的步骤 6 中注册)。

 package com.mkyong.common.controller;import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.mkyong.common.model.SampleContent;@Controller
public class RssController {@RequestMapping(value="/rssfeed", method = RequestMethod.GET)public ModelAndView getFeedInRss() {List<SampleContent> items = new ArrayList<SampleContent>();SampleContent content  = new SampleContent();content.setTitle("Spring MVC Tutorial 1");content.setUrl("http://www.mkyong.com/spring-mvc/tutorial-1");content.setSummary("Tutorial 1 summary ...");content.setCreatedDate(new Date());items.add(content);SampleContent content2  = new SampleContent();content2.setTitle("Spring MVC Tutorial 2");content2.setUrl("http://www.mkyong.com/spring-mvc/tutorial-2");content2.setSummary("Tutorial 2 summary ...");content2.setCreatedDate(new Date());items.add(content2);ModelAndView mav = new ModelAndView();mav.setViewName("rssViewer");mav.addObject("feedContent", items);return mav;}} 

6.春豆注册

在一个 Spring bean 定义文件中,启用自动组件扫描,并注册您的“CustomRssViewer”类和“BeanNameViewResolver”视图解析器,这样当视图名“ rssViewer ”返回时,Spring 知道它应该映射到 bean id“RSS viewer”。

文件:mvc-dispatcher-servlet.xml

 <beans xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"><context:component-scan base-package="com.mkyong.common.controller" /><!-- Map returned view name "rssViewer" to bean id "rssViewer" --><bean class="org.springframework.web.servlet.view.BeanNameViewResolver" /><bean id="rssViewer" class="com.mkyong.common.rss.CustomRssViewer" /></beans> 

Note
File content of web.xml is omitted, just a standard configuration, if you are interest, download this whole project at the end of the article.

7.演示

网址:http://localhost:8080/spring MVC/rest/RSS feed

spring mvc and rss feed demoHow about Atom?
For Atom, you just need to extends AbstractAtomFeedView, instead of AbstractRssFeedView.

下载源代码

Download it – SpringMVC-RSS-Feed-Example.zip (9 KB)

参考

  1. 罗马–RSS 提要的 Java 库
  2. 【javadoc 摘要种子
  3. 用 Java 创建 RSS 提要的例子

rss spring mvc spring3

Spring 3 MVC 和 XML 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-3-mvc-and-xml-example/

在 Spring 3 中,“ mvc:annotation-driven ”的一个特性是支持将对象转换为 XML 文件,如果 JAXB 在项目类路径中的话。

在本教程中,我们将向您展示如何将返回对象转换为 XML 格式,并通过 Spring @MVC 框架将其返回给用户。

使用的技术:

  1. 弹簧 3.0.5 释放
  2. JDK 1.6
  3. Eclipse 3.6
  4. maven3

JAXB in JDK6
JAXB is included in JDK6, so, you do not need to include JAXB library manually, as long as object is annotated with JAXB annotation, Spring will convert it into XML format automatically.

1.项目相关性

没有额外的依赖,你只需要在你的 Maven pom.xml中包含 Spring MVC。

 <properties><spring.version>3.0.5.RELEASE</spring.version></properties><dependencies><!-- Spring 3 dependencies --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency></dependencies> 

2.模型+ JAXB

一个简单的 POJO 模型并用 JAXB 注释进行了注释,稍后将这个对象转换成 XML 输出。

 package com.mkyong.common.model;import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;@XmlRootElement(name = "coffee")
public class Coffee {String name;int quanlity;public String getName() {return name;}@XmlElementpublic void setName(String name) {this.name = name;}public int getQuanlity() {return quanlity;}@XmlElementpublic void setQuanlity(int quanlity) {this.quanlity = quanlity;}public Coffee(String name, int quanlity) {this.name = name;this.quanlity = quanlity;}public Coffee() {}} 

3.控制器

在方法返回值中添加“@ response body”,Spring 文档中没有太多细节。

据我所知,当春天来临

  1. 用 JAXB 注释的对象
  2. 类路径中存在 JAXB 库
  3. 启用“mvc:注释驱动”
  4. 用@ResponseBody 批注的返回方法

它会自动处理转换。

 package com.mkyong.common.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.mkyong.common.model.Coffee;@Controller
@RequestMapping("/coffee")
public class XMLController {@RequestMapping(value="{name}", method = RequestMethod.GET)public @ResponseBody Coffee getCoffeeInXML(@PathVariable String name) {Coffee coffee = new Coffee(name, 100);return coffee;}} 

4.mvc:注释驱动

在您的一个 Spring 配置 XML 文件中,启用“mvc:annotation-driven”。

 <beans xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"><context:component-scan base-package="com.mkyong.common.controller" /><mvc:annotation-driven /></beans> 

Note
Alternatively, you can declares “spring-oxm.jar” dependency and include following MarshallingView, to handle the conversion. With this method, you don’t need annotate @ResponseBody in your method.

 <beans ...><bean class="org.springframework.web.servlet.view.BeanNameViewResolver" /><bean id="xmlViewer" class="org.springframework.web.servlet.view.xml.MarshallingView"><constructor-arg><bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller"><property name="classesToBeBound"><list><value>com.mkyong.common.model.Coffee</value></list></property></bean></constructor-arg></bean>
</beans> 

5.演示

网址:http://localhost:8080/spring MVC/rest/coffee/arabica

spring mvc and xml example demo

下载源代码

Download it – SpringMVC-XML-Example.zip (7 KB)

参考

  1. Spring MVC 和 Rss 示例
  2. mvc 注释驱动的 JavaDoc
  3. Jaxb2Marshaller JavaDoc
  4. ResponseBody.html·哈瓦多克

spring mvc spring3 xml

spring 3 MVC ContentNegotiatingViewResolver 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-3-mvc-contentnegotiatingviewresolver-example/

Spring 3,contentnegotiatingviewrolver,是一个有趣的视图解析器,它允许你输出相同的资源(内容或数据)到不同类型的视图,如 JSPXMLRSSJSON 等。简单地说,看下面的 web 请求的 URL,它将在不同的视图中返回。

  1. http://www.mkyong.com/fruit/banana.rss,作为 RSS 文件返回。
  2. http://www.mkyong.com/fruit/banana.xml,以 XML 文件形式返回。
  3. http://www.mkyong.com/fruit/banana.json,作为 JSON 文件返回。
  4. http://www.mkyong.com/fruit/banana,返回到您的默认视图解析器。

Note
This ContentNegotiatingViewResolver first determine “which view resolver should return by file extension”, if no view is match, then use the default view resolver. Read this Spring documentation to study how it works.

在本教程中,我们将向您展示如何使用ContentNegotiatingViewResolver。在本教程结束时,根据请求的文件扩展名,相同的模型将以不同的视图返回——XML、JSON、RSS 和 JSP。

使用的技术:

  1. 弹簧 3.0.5 释放
  2. 杰克逊 1.7.1
  3. 罗马 1.0.0
  4. JDK 1.6
  5. maven3
  6. Eclipse 3.6

Note
JAXB is bundled in JDK1.6, so, you don’t need to include it manually.

1.项目依赖性

在 Maven pom.xml文件中声明以下依赖关系。

 <properties><spring.version>3.0.5.RELEASE</spring.version></properties><dependencies><!-- Spring 3 dependencies --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!-- Jackson JSON Mapper --><dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-mapper-asl</artifactId><version>1.7.1</version></dependency><!-- RSS --><dependency><groupId>net.java.dev.rome</groupId><artifactId>rome</artifactId><version>1.0.0</version></dependency></dependencies></project> 

2.模型

一个 Pojo,用 JAXB 注释进行了注释,因此它可以在 XML 文件中输出。除此之外,以后我们用这个模型来显示不同的视图。

 package com.mkyong.common.model;import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;@XmlRootElement(name = "fruit")
public class Fruit {String name;int quality;public String getName() {return name;}@XmlElementpublic void setName(String name) {this.name = name;}public int getQuality() {return quality;}@XmlElementpublic void setQuality(int quality) {this.quality = quality;}public Fruit(String name, int quality) {this.name = name;this.quality = quality;}public Fruit() {}} 

3.JSON 和 XML 视图

要输出 JSON 和 XML 视图,你不需要做任何额外的工作,Spring MVC 会自动处理转换。阅读这个 Spring MVC 和 XML ,以及 Spring MVC 和 JSON 的例子。

4.RSS 视图

要输出 RSS 视图,需要扩展AbstractRssFeedView。阅读这个 Spring 3 MVC 和 RSS 示例来了解它是如何工作的。

 package com.mkyong.common.rss;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.view.feed.AbstractRssFeedView;
import com.mkyong.common.model.Fruit;
import com.sun.syndication.feed.rss.Channel;
import com.sun.syndication.feed.rss.Content;
import com.sun.syndication.feed.rss.Item;public class RssFeedView extends AbstractRssFeedView {@Overrideprotected void buildFeedMetadata(Map<String, Object> model, Channel feed,HttpServletRequest request) {feed.setTitle("Sample Title");feed.setDescription("Sample Description");feed.setLink("http://google.com");super.buildFeedMetadata(model, feed, request);}@Overrideprotected List<Item> buildFeedItems(Map<String, Object> model,HttpServletRequest request, HttpServletResponse response)throws Exception {Fruit fruit = (Fruit) model.get("model");String msg = fruit.getName() + fruit.getQuality();List<Item> items = new ArrayList<Item>(1);Item item = new Item();item.setAuthor("mkyong");item.setLink("http://www.mkyong.com");Content content = new Content();content.setValue(msg);item.setContent(content);items.add(item);return items;}
} 

5.JSP 视图

显示模型数据的 JSP 页面。

文件:list.jsp

 <html>
<body><h1>Spring @MVC ContentNegotiatingViewResolver</h1>Fruit Name : ${model.name} <br />Fruit Quality : ${model.quality}</body>
</html> 

6.控制器

Spring 控制器,生成一个“水果”模型并返回它。

 package com.mkyong.common.controller;import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.mkyong.common.model.Fruit;@Controller
@RequestMapping("/fruit")
public class FruitController {@RequestMapping(value="{fruitName}", method = RequestMethod.GET)public String getFruit(@PathVariable String fruitName, ModelMap model) {Fruit fruit = new Fruit(fruitName, 1000);model.addAttribute("model", fruit);return "list";}} 

7.ContentNegotiatingViewResolver 示例

代码应该是不言自明的。但是,您必须定义" order 属性,其中较低的值获得较高的优先级。在这种情况下,当请求一个 URL 时,Spring MVC 将使用“ContentNegotiatingViewResolver”(order = 1)返回一个合适的视图(基于“mediaTypes”属性中声明的文件扩展名),如果不匹配,则使用“InternalResourceViewResolver”(order = 2)返回一个默认的 JSP 页面。

 <beans xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"><context:component-scan base-package="com.mkyong.common.controller" /><mvc:annotation-driven /><bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"><property name="order" value="1" /><property name="mediaTypes"><map><entry key="json" value="application/json" /><entry key="xml" value="application/xml" /><entry key="rss" value="application/rss+xml" /></map></property><property name="defaultViews"><list><!-- JSON View --><beanclass="org.springframework.web.servlet.view.json.MappingJacksonJsonView"></bean><!-- RSS View --><bean class="com.mkyong.common.rss.RssFeedView" /><!-- JAXB XML View --><bean class="org.springframework.web.servlet.view.xml.MarshallingView"><constructor-arg><bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller"><property name="classesToBeBound"><list><value>com.mkyong.common.model.Fruit</value></list></property></bean></constructor-arg></bean></list></property><property name="ignoreAcceptHeader" value="true" /></bean><!-- If no extension matched, use JSP view --><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="order" value="2" /><property name="prefix"><value>/WEB-INF/pages/</value></property><property name="suffix"><value>.jsp</value></property></bean></beans> 

8.演示

通过ContentNegotiatingViewResolver在不同的视图中显示相同的型号。

http://localhost:8080/spring MVC/fruit/banana . xml,显示为 XML 文件。

spring mvc and xml demo

http://localhost:8080/spring MVC/fruit/banana . json,显示为 JSON 文件。

spring mvc and json demo

http://localhost:8080/spring MVC/fruit/banana . rss,显示为 RSS 文件。

spring mvc and RSS demo

http://localhost:8080/spring MVC/fruit/banana,显示为 JSP 页面。

spring mvc and JSP demo

下载源代码

Download it – SpringMVC-ContentNegotiatingViewResolver-Example.zip (10 KB)

参考

  • Spring ContentNegotiatingViewResolver JavaDoc
  • 使用 Spring MVC 的 ContentNegotiatingViewResolver 进行内容协商
  • 另一个 ContentNegotiatingViewResolver 示例
  • Spring 3 MVC 和 RSS feed 示例
  • Spring 3 MVC 和 XML 示例
  • Spring 3 MVC 和 JSON 示例

spring mvc spring3

Spring 3 MVC hello world 示例–注释

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-3-mvc-hello-world-example-annotation/

在本教程中,我们将采用之前的 Maven + Spring MVC XML 示例,重写它以支持@JavaConfig配置,不再需要 XML 文件,并将其部署到 Servlet 3.0+容器中,如 Tomcat 7 或 Jetty 9。

使用的技术:

  1. 释放弹簧
  2. maven3
  3. JDK 1.6
  4. Tomcat 7 或 Jetty 9
  5. Eclipse 4.4
  6. 3 号艇

Spring 4 MVC Annotation
Try this Spring 4 MVC hello world example – Annotation.

1.项目结构

下载项目源代码并查看项目文件夹结构:

spring3-mvc-hello-world-annotation

没有像web.xml这样的 XML 文件或任何其他 Spring XML 配置文件。

2.专家

2.1 一个pom.xml模板快速启动一个 Spring MVC 项目。为了编译这个项目,我们需要添加一个servlet-api依赖项。

pom.xml

 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>spring3-mvc-maven-annotation-hello-world</artifactId><packaging>war</packaging><version>1.0-SNAPSHOT</version><name>spring mvc</name><properties><jdk.version>1.6</jdk.version><spring.version>3.2.13.RELEASE</spring.version><jstl.version>1.2</jstl.version><servletapi.version>3.1.0</servletapi.version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>${jstl.version}</version></dependency><!-- compile only, deployed container will provide this --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>${servletapi.version}</version><scope>provided</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.3</version><configuration><source>${jdk.version}</source><target>${jdk.version}</target></configuration></plugin><!-- embedded Jetty server, for testing --><plugin><groupId>org.eclipse.jetty</groupId><artifactId>jetty-maven-plugin</artifactId><version>9.2.11.v20150529</version><configuration><scanIntervalSeconds>10</scanIntervalSeconds><webApp><contextPath>/spring3</contextPath></webApp></configuration></plugin><!-- configure Eclipse workspace --> <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-eclipse-plugin</artifactId><version>2.9</version><configuration><downloadSources>true</downloadSources><downloadJavadocs>true</downloadJavadocs><wtpversion>2.0</wtpversion><wtpContextName>spring3</wtpContextName></configuration></plugin></plugins></build></project> 

2.2 编译这个项目并使它支持 Eclipse IDE。

Terminal

 $ mvn eclipse:eclipse 

3.弹簧控制器

HelloController.java

 package com.mkyong.web.controller;import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;@Controller
public class HelloController {@RequestMapping(value = "/", method = RequestMethod.GET)public String printWelcome(ModelMap model) {model.addAttribute("message", "Spring 3 MVC Hello World");return "hello";}@RequestMapping(value = "/hello/{name:.+}", method = RequestMethod.GET)public ModelAndView hello(@PathVariable("name") String name) {ModelAndView model = new ModelAndView();model.setViewName("hello");model.addObject("msg", name);return model;}} 

4.JSP 视图

显示值的 JSP 页面,包括引导 css 和 js。

html4strict

 <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Maven + Spring MVC + @JavaConfig</title><spring:url value="/resources/core/css/hello.css" var="coreCss" />
<spring:url value="/resources/core/css/bootstrap.min.css" var="bootstrapCss" />
<link href="${bootstrapCss}" rel="stylesheet" />
<link href="${coreCss}" rel="stylesheet" />
</head><nav class="navbar navbar-inverse navbar-fixed-top"><div class="container"><div class="navbar-header"><a class="navbar-brand" href="#">Spring 3 MVC Project @JavaConfig</a></div></div>
</nav><div class="jumbotron"><div class="container"><h1>${title}</h1><p><c:if test="${not empty name}">Hello ${name}</c:if><c:if test="${empty name}">Welcome Welcome!</c:if></p><p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p></div>
</div><div class="container"><div class="row"><div class="col-md-4"><h2>Heading</h2><p>ABC</p><p><a class="btn btn-default" href="#" role="button">View details</a></p></div><div class="col-md-4"><h2>Heading</h2><p>ABC</p><p><a class="btn btn-default" href="#" role="button">View details</a></p></div><div class="col-md-4"><h2>Heading</h2><p>ABC</p><p><a class="btn btn-default" href="#" role="button">View details</a></p></div></div><hr><footer><p>© Mkyong.com 2015</p></footer>
</div><spring:url value="/resources/core/css/hello.js" var="coreJs" />
<spring:url value="/resources/core/css/bootstrap.min.js" var="bootstrapJs" /><script src="${coreJs}"></script>
<script src="${bootstrapJs}"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script></body>
</html> 

5.Spring @JavaConfig

SpringWebConfig.java

 package com.mkyong.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;@EnableWebMvc //mvc:annotation-driven
@Configuration
@ComponentScan({ "com.mkyong.web" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");}@Beanpublic InternalResourceViewResolver viewResolver() {InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();viewResolver.setViewClass(JstlView.class);viewResolver.setPrefix("/WEB-INF/views/jsp/");viewResolver.setSuffix(".jsp");return viewResolver;}} 

XML 等价物。

 <beans xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"><context:component-scan base-package="com.mkyong.web" /><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix"><value>/WEB-INF/views/jsp/</value></property><property name="suffix"><value>.jsp</value></property></bean><mvc:resources mapping="/resources/**" location="/resources/" /><mvc:annotation-driven /></beans> 

6.Servlet 3.0+容器

通过扩展AbstractAnnotationConfigDispatcherServletInitializer创建一个 ServletInitializer 类,Servlet 3.0+容器将自动获取这个类并运行它。这是对web.xml的替代。

MyWebInitializer.java

 package com.mkyong.servlet3;import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;import com.mkyong.config.SpringWebConfig;public class MyWebInitializer extendsAbstractAnnotationConfigDispatcherServletInitializer {@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[] { SpringWebConfig.class };}@Overrideprotected String[] getServletMappings() {return new String[] { "/" };}@Overrideprotected Class<?>[] getRootConfigClasses() {return null;}} 

7.演示

下载项目并使用嵌入的 Jetty 容器运行它。

Terminal

 $ mvn jetty:run 

网址:http://localhost:8080/spring 3

spring3-mvc-maven-xml-demo

网址:http://localhost:8080/spring 3/hello/mkyong

spring3-mvc-maven-xml-demo2

下载源代码

Download it – spring3-mvc-maven-annotation-hello-world (47 KB)Github link – spring3-mvc-maven-annotation-hello-world.git

参考

  1. 春季新品 3
  2. Spring 3 MVC 和 XML 示例
  3. Spring 3 MVC 和 JSON 示例

maven spring config spring mvc spring3

Spring MVC hello world 示例(Maven 和百里香叶)

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-3-mvc-hello-world-example/

本教程向您展示了如何使用百里香叶模板创建一个 Spring Web MVC 应用程序。

使用的技术和工具:

  • Java 11
  • 释放弹簧
  • 百里香叶
  • 嵌入式 Jetty 服务器 9.4.45.v20220203
  • Servlet API 4.0.4
  • Bootstrap 5.2.0 (webjars)
  • 智能理念
  • Maven 3.8.6
  • 弹簧测试 5.2.22 .释放
  • 哈姆克雷斯特 2.2
  • JUnit 5.9

目录:

  • 1。Spring Web MVC 基础
  • 2。目录结构
  • 3。项目依赖性
  • 4。项目依赖关系——树形格式
  • 5。弹簧控制器
  • 6。弹簧配置
  • 7。Spring DispatcherServlet
  • 8。查看(百里香叶)
  • 9。Spring MVC 和单元测试
  • 10。演示
  • 11。下载源代码
  • 10。参考文献


本教程不是 Spring Boot 应用,只是纯 Spring Web MVC!

1。Spring Web MVC 基础

在 Spring Web MVC 中,它由 3 个标准的 MVC (模型、视图、控制器)组件组成:

  • Models–包含数据。
  • Views–使用视图技术显示数据,如百里香、FreeMarker、Groovy 标记、脚本视图(Mustache、React 等)。),或者经典的 JSP 和 JSTL。
  • Controllers–接受输入,修改它们,并传递给模型或视图。

Spring Web MVC 的核心组件是DispatcherServlet,它充当前端控制器模式。每个 web 请求都必须经过这个DispatcherServletDispatcherServlet会将 web 请求分派给注册的处理程序或组件。

下图演示了 Spring MVC web 应用程序如何处理 web 请求。

spring web mvc DispatcherServlet

图 1.1 :图片复制自 Spring MVC 参考,稍加修改。


请参考官方 Spring Web MVC doc 。

2。目录结构

下面是这个项目的标准 Maven 目录结构。

directory structure

3。项目依赖性

以下是该项目的核心依赖项;spring-webmvc依赖是必须的,但是其他的依赖依赖于你的项目需求。

  • spring-webmvc–用于 Spring core 相关的 web 组件。
  • thymeleaf-spring5–用于百里香视图模板和 Spring 5 集成。
  • org.webjars.bootstrap–用于 WebJars 管理客户端 web 库,例如 bootstrap。
  • jakarta.servlet-api–我们需要 servlet-api 来编译 web 应用程序,设置为provided范围;通常,嵌入式服务器会提供这种功能。
  • maven-compiler-plugin–编译项目。
  • jetty-maven-plugin–在嵌入式 Jetty 服务器中运行这个项目,就像mvn jetty:run一样。

pom.xml

 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>spring-mvc-hello-world</artifactId><packaging>war</packaging><version>1.0-SNAPSHOT</version><name>spring web mvc</name><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><jdk.version>11</jdk.version><spring.version>5.2.22.RELEASE</spring.version><servletapi.version>4.0.4</servletapi.version><thymeleaf.spring.version>3.0.15.RELEASE</thymeleaf.spring.version><webjars.version>5.2.0</webjars.version><hamcrest.version>2.2</hamcrest.version><junit.version>5.9.0</junit.version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring5</artifactId><version>${thymeleaf.spring.version}</version></dependency><dependency><groupId>org.webjars</groupId><artifactId>bootstrap</artifactId><version>${webjars.version}</version></dependency><dependency><groupId>jakarta.servlet</groupId><artifactId>jakarta.servlet-api</artifactId><version>${servletapi.version}</version><scope>provided</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>${junit.version}</version><scope>test</scope></dependency><dependency><groupId>org.hamcrest</groupId><artifactId>hamcrest-core</artifactId><version>${hamcrest.version}</version><scope>test</scope></dependency><!-- compile only, deployed container will provide this --><!--<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>${servletapi.version}</version><scope>provided</scope></dependency>--></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.10.1</version><configuration><source>${jdk.version}</source><target>${jdk.version}</target></configuration></plugin><plugin><groupId>org.eclipse.jetty</groupId><artifactId>jetty-maven-plugin</artifactId><version>9.4.45.v20220203</version><configuration><scanIntervalSeconds>10</scanIntervalSeconds><webApp><contextPath>/spring</contextPath></webApp></configuration></plugin></plugins></build></project> 

4。项目依赖关系——树形格式

再次检查树结构中的项目依赖关系。

Terminal

 mvn dependency:tree[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< com.mkyong:spring-mvc-hello-world >------------------
[INFO] Building spring web mvc 1.0-SNAPSHOT
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ spring-mvc-hello-world ---
[INFO] com.mkyong:spring-mvc-hello-world:war:1.0-SNAPSHOT
[INFO] +- org.springframework:spring-webmvc:jar:5.2.22.RELEASE:compile
[INFO] |  +- org.springframework:spring-aop:jar:5.2.22.RELEASE:compile
[INFO] |  +- org.springframework:spring-beans:jar:5.2.22.RELEASE:compile
[INFO] |  +- org.springframework:spring-context:jar:5.2.22.RELEASE:compile
[INFO] |  +- org.springframework:spring-core:jar:5.2.22.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-jcl:jar:5.2.22.RELEASE:compile
[INFO] |  +- org.springframework:spring-expression:jar:5.2.22.RELEASE:compile
[INFO] |  \- org.springframework:spring-web:jar:5.2.22.RELEASE:compile
[INFO] +- org.thymeleaf:thymeleaf-spring5:jar:3.0.15.RELEASE:compile
[INFO] |  +- org.thymeleaf:thymeleaf:jar:3.0.15.RELEASE:compile
[INFO] |  |  +- org.attoparser:attoparser:jar:2.0.5.RELEASE:compile
[INFO] |  |  \- org.unbescape:unbescape:jar:1.1.6.RELEASE:compile
[INFO] |  \- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] +- org.webjars:bootstrap:jar:5.2.0:compile
[INFO] +- jakarta.servlet:jakarta.servlet-api:jar:4.0.4:provided
[INFO] +- org.springframework:spring-test:jar:5.2.22.RELEASE:test
[INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.9.0:test
[INFO] |  +- org.junit.platform:junit-platform-engine:jar:1.9.0:test
[INFO] |  |  +- org.opentest4j:opentest4j:jar:1.2.0:test
[INFO] |  |  \- org.junit.platform:junit-platform-commons:jar:1.9.0:test
[INFO] |  +- org.junit.jupiter:junit-jupiter-api:jar:5.9.0:test
[INFO] |  \- org.apiguardian:apiguardian-api:jar:1.1.2:test
[INFO] \- org.hamcrest:hamcrest-core:jar:2.2:test
[INFO]    \- org.hamcrest:hamcrest:jar:2.2:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.877 s
[INFO] Finished at: 2022-09-23T20:17:05+08:00
[INFO] ------------------------------------------------------------------------ 

5。弹簧控制器

下面是一个 Spring Web MVC 控制器,用于处理对//hello/{name}的 Web 请求并显示消息。

HelloController.java

 package com.mkyong.web;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;@Controller
public class HelloController {@RequestMapping(value = "/", method = RequestMethod.GET)public String welcome(ModelMap model) {model.addAttribute("message", "Spring MVC Hello World");// view name, map to welcome.html laterreturn "welcome";}@GetMapping("/hello/{name:.+}")public String hello(Model model, @PathVariable("name") String name) {model.addAttribute("message", name);// view name, map to welcome.html laterreturn "welcome";}} 

6。弹簧配置

对于 Spring 配置,实现WebMvcConfigurer并覆盖所需的方法,或者在这里声明额外的 beans,例如,Spring + Thymeleaf 视图解析器等。


更详细的解释请参考官方百里香+春光融合的文件。

SpringWebConfig.java

 package com.mkyong.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;@EnableWebMvc
@Configuration
@ComponentScan({"com.mkyong.web"})
public class SpringWebConfig implements WebMvcConfigurer {// Spring + Thymeleaf need this@Autowiredprivate ApplicationContext applicationContext;@Overridepublic void addResourceHandlers(final ResourceHandlerRegistry registry) {registry.addResourceHandler("/css/**").addResourceLocations("/resources/core/css/");registry.addResourceHandler("/js/**").addResourceLocations("/resources/core/js/");registry.addResourceHandler("/webjars/**").addResourceLocations("/webjars/");}// Spring + Thymeleaf@Beanpublic SpringResourceTemplateResolver templateResolver() {SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();templateResolver.setApplicationContext(this.applicationContext);templateResolver.setPrefix("/WEB-INF/views/thymeleaf/");templateResolver.setSuffix(".html");templateResolver.setTemplateMode(TemplateMode.HTML);templateResolver.setCacheable(true);return templateResolver;}// Spring + Thymeleaf@Beanpublic SpringTemplateEngine templateEngine() {SpringTemplateEngine templateEngine = new SpringTemplateEngine();templateEngine.setTemplateResolver(templateResolver());templateEngine.setEnableSpringELCompiler(true);return templateEngine;}// Spring + Thymeleaf// Configure Thymeleaf View Resolver@Beanpublic ThymeleafViewResolver viewResolver() {ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();viewResolver.setTemplateEngine(templateEngine());return viewResolver;}} 

7。Spring DispatcherServlet

我们可以扩展AbstractAnnotationConfigDispatcherServletInitializer来注册DispatcherServlet,这样 Servlet 容器就知道在哪里可以找到上面的 Spring 配置SpringWebConfig来加载和启动 Spring Web MVC 应用程序。

这个MyServletInitializer将由 Servlet 容器自动检测(例如,Jetty 或 Tomcat)。

MyServletInitializer.java

 package com.mkyong;import com.mkyong.config.SpringWebConfig;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;public class MyServletInitializerextends AbstractAnnotationConfigDispatcherServletInitializer {// services and data sources@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[0];}// controller, view resolver, handler mapping@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[]{SpringWebConfig.class};}@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}
} 

8。查看(百里香叶)

一个显示 hello world 消息的简单 Thylemeaf 模板也展示了如何集成 webjars 的引导和定制 CSS 和 JS 文件。

webapp/WEB-INF/template/welcome.html

 <!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><title>Spring Web MVC Thymeleaf Hello World Example</title><!-- Boostrap core css --><link rel="stylesheet" th:href="@{/webjars/bootstrap/5.2.0/css/bootstrap.min.css}"/><!-- custom style --><link rel="stylesheet" th:href="@{/css/main.css}"/></head><body><nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top"><a class="navbar-brand" href="#">Mkyong.com</a>
</nav><main role="main" class="container"><div class="starter-template"><h1>Spring Web MVC Thymeleaf Example</h1><h2><span th:text="'Hello, ' + ${message}"></span></h2></div></main>
<!-- /.container --><!-- Boostrap core js -->
<script type="text/javascript" th:src="@{webjars/bootstrap/5.2.0/js/bootstrap.min.js}"></script>
</body>
</html> 

9。Spring MVC 和单元测试

Spring MVC 5 和 JUnit 5 的例子。

HelloControllerTest.java

 package com.mkyong;import com.mkyong.config.SpringWebConfig;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.ModelAndView;import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextConfiguration(classes = {SpringWebConfig.class})
public class HelloControllerTest {@Autowiredprivate WebApplicationContext wac;private MockMvc mockMvc;@BeforeEachvoid setup() {this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();}@Testpublic void testDefaultPage() throws Exception {MvcResult result = this.mockMvc.perform(get("/"))/*.andDo(print())*/.andExpect(status().isOk()).andReturn();ModelAndView modelAndView = result.getModelAndView();assertEquals("welcome", modelAndView.getViewName());assertEquals("Spring MVC Hello World", modelAndView.getModel().get("message"));}@Testpublic void testHelloPage() throws Exception {MvcResult result = this.mockMvc.perform(get("/hello/mkyong")).andExpect(status().isOk()).andReturn();ModelAndView modelAndView = result.getModelAndView();assertEquals("welcome", modelAndView.getViewName());assertEquals("mkyong", modelAndView.getModel().get("message"));}} 

10。演示

进入终端,项目文件夹,运行mvn jetty:run

Terminal

 mvn jetty:run...
[INFO] Started ServerConnector@5b3755f4{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
[INFO] Started @3134ms
[INFO] Started Jetty Server 

Spring Web MVC 应用程序默认部署在端口8080的 Jetty 容器中。

http://localhost:8080/spring

spring web mvc hello world demo 1

http://localhost:8080/spring/hello/mkyong

spring web mvc hello world demo 2

11。下载源代码

$ git 克隆https://github.com/mkyong/spring-mvc/

$ cd spring-mvc-hello-world

$ mvn 清洁码头:运行

请访问 http://localhost:8080/spring

请访问 http://localhost:8080/spring/hello/mkyong

10。参考文献

  • 教程:百里香叶+春天
  • 维基百科–模型–视图–控制器
  • Spring Boot Hello World 示例–百里香叶
  • Spring MVC hello world 示例(Gradle 和 JSP)

Spring 4 MVC Ajax Hello World 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-4-mvc-ajax-hello-world-example/

在本教程中,我们将向您展示如何创建一个 Spring MVC web 项目并通过 Ajax 提交表单。

使用的技术:

  1. 弹簧 4.2.2 释放
  2. 杰克逊 2.6.3
  3. 回溯 1.1.3
  4. jQuery 1.10
  5. maven3
  6. JDK 1.8
  7. Tomcat 8 或 Jetty 9
  8. Eclipse 4.5
  9. 3 号艇

如果在项目类路径中找到了 Jackson 库,Spring 将使用 Jackson 自动处理 json 数据与对象之间的转换。

Note
Try this – Spring Boot Ajax example

1.快速参考

1.1 在 HTML 中,使用 jQuery [$.ajax()](http://web.archive.org/web/20190215000820/http://api.jquery.com/jquery.ajax/)发送表单请求。

 jQuery(document).ready(function($) {$("#search-form").submit(function(event) {// Prevent the form from submitting via the browser.event.preventDefault();searchViaAjax();});});function searchAjax() {var data = {}data["query"] = $("#query").val();$.ajax({type : "POST",contentType : "application/json",url : "${home}search/api/getSearchResult",data : JSON.stringify(data),dataType : 'json',timeout : 100000,success : function(data) {console.log("SUCCESS: ", data);display(data);},error : function(e) {console.log("ERROR: ", e);display(e);},done : function(e) {console.log("DONE");}});} 

1.2 Spring 控制器处理 Ajax 请求。

 @Controller
public class AjaxController {@ResponseBody@RequestMapping(value = "/search/api/getSearchResult")public AjaxResponseBody getSearchResultViaAjax(@RequestBody SearchCriteria search) {AjaxResponseBody result = new AjaxResponseBody();//logicreturn result;}} 

2.项目目录

查看项目目录,这是一个标准的 Maven 项目目录结构。

spring-mvc-ajax-example-1 ## 3.项目相关性

pom.xml

 <project  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>spring4-mvc-maven-ajax-example</artifactId><packaging>war</packaging><version>1.0-SNAPSHOT</version><name>spring4 mvc maven ajax example</name><properties><jdk.version>1.8</jdk.version><spring.version>4.2.2.RELEASE</spring.version><jackson.version>2.6.3</jackson.version><logback.version>1.1.3</logback.version><jcl.slf4j.version>1.7.12</jcl.slf4j.version><jstl.version>1.2</jstl.version><servletapi.version>3.1.0</servletapi.version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version><exclusions><exclusion><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId></exclusion></exclusions></dependency><!-- Need this for json to/from object --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>${jackson.version}</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>${jackson.version}</version></dependency><!-- JSTL for views --><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>${jstl.version}</version></dependency><!-- Logging --><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>${jcl.slf4j.version}</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>${logback.version}</version></dependency><!-- compile only, runtime container will provide this --><!-- Need this for config annotation --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>${servletapi.version}</version><scope>provided</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.3</version><configuration><source>${jdk.version}</source><target>${jdk.version}</target></configuration></plugin><plugin><groupId>org.eclipse.jetty</groupId><artifactId>jetty-maven-plugin</artifactId><version>9.2.11.v20150529</version><configuration><scanIntervalSeconds>10</scanIntervalSeconds><webApp><contextPath>/spring4ajax</contextPath></webApp></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-eclipse-plugin</artifactId><version>2.10</version><configuration><downloadSources>true</downloadSources><downloadJavadocs>true</downloadJavadocs><wtpversion>2.0</wtpversion><wtpContextName>spring4ajax</wtpContextName></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-war-plugin</artifactId><version>2.6</version><configuration><failOnMissingWebXml>false</failOnMissingWebXml></configuration></plugin><!-- Deploy to WildFly --><plugin><groupId>org.wildfly.plugins</groupId><artifactId>wildfly-maven-plugin</artifactId><version>1.1.0.Alpha5</version><configuration><hostname>127.0.0.1</hostname><port>9990</port><username>admin</username><password>admin</password><name>spring4ajax.war</name></configuration></plugin></plugins></build></project> 

4.弹簧组件

只会显示重要的类。

4.1 @RestController处理 Ajax 请求。阅读评论,不言自明。

AjaxController.java

 package com.mkyong.web.controller;import java.util.ArrayList;
import java.util.List;import javax.annotation.PostConstruct;import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import com.fasterxml.jackson.annotation.JsonView;
import com.mkyong.web.jsonview.Views;
import com.mkyong.web.model.AjaxResponseBody;
import com.mkyong.web.model.SearchCriteria;
import com.mkyong.web.model.User;@RestController
public class AjaxController {List<User> users;// @ResponseBody, not necessary, since class is annotated with @RestController// @RequestBody - Convert the json data into object (SearchCriteria) mapped by field name.// @JsonView(Views.Public.class) - Optional, filters json data to display.@JsonView(Views.Public.class)@RequestMapping(value = "/search/api/getSearchResult")public AjaxResponseBody getSearchResultViaAjax(@RequestBody SearchCriteria search) {AjaxResponseBody result = new AjaxResponseBody();if (isValidSearchCriteria(search)) {List<User> users = findByUserNameOrEmail(search.getUsername(), search.getEmail());if (users.size() > 0) {result.setCode("200");result.setMsg("");result.setResult(users);} else {result.setCode("204");result.setMsg("No user!");}} else {result.setCode("400");result.setMsg("Search criteria is empty!");}//AjaxResponseBody will be converted into json format and send back to the request.return result;}private boolean isValidSearchCriteria(SearchCriteria search) {boolean valid = true;if (search == null) {valid = false;}if ((StringUtils.isEmpty(search.getUsername())) && (StringUtils.isEmpty(search.getEmail()))) {valid = false;}return valid;}// Init some users for testing@PostConstructprivate void iniDataForTesting() {users = new ArrayList<User>();User user1 = new User("mkyong", "pass123", "mkyong@yahoo.com", "012-1234567", "address 123");User user2 = new User("yflow", "pass456", "yflow@yahoo.com", "016-7654321", "address 456");User user3 = new User("laplap", "pass789", "mkyong@yahoo.com", "012-111111", "address 789");users.add(user1);users.add(user2);users.add(user3);}// Simulate the search functionprivate List<User> findByUserNameOrEmail(String username, String email) {List<User> result = new ArrayList<User>();for (User user : users) {if ((!StringUtils.isEmpty(username)) && (!StringUtils.isEmpty(email))) {if (username.equals(user.getUsername()) && email.equals(user.getEmail())) {result.add(user);continue;} else {continue;}}if (!StringUtils.isEmpty(username)) {if (username.equals(user.getUsername())) {result.add(user);continue;}}if (!StringUtils.isEmpty(email)) {if (email.equals(user.getEmail())) {result.add(user);continue;}}}return result;}
} 

4.2“JSON 数据”将通过@RequestBody转换成该对象。

SearchCriteria.java

 package com.mkyong.web.model;public class SearchCriteria {String username;String email;//getters and setters
} 

4.2 为@JsonView创建一个虚拟类,以控制应该返回给请求的内容。

Views.java

 package com.mkyong.web.jsonview;public class Views {public static class Public {}
} 

4.3 搜索功能的用户对象。将显示标注有@JsonView的字段。

User.java

 package com.mkyong.web.model;import com.fasterxml.jackson.annotation.JsonView;
import com.mkyong.web.jsonview.Views;public class User {@JsonView(Views.Public.class)String username;String password;@JsonView(Views.Public.class)String email;@JsonView(Views.Public.class)String phone;String address;//getters, setters and contructors
} 

4.4 这个对象将被转换成 json 格式并返回给请求。

AjaxResponseBody.java

 package com.mkyong.web.model;import java.util.List;
import com.fasterxml.jackson.annotation.JsonView;
import com.mkyong.web.jsonview.Views;public class AjaxResponseBody {@JsonView(Views.Public.class)String msg;@JsonView(Views.Public.class)String code;@JsonView(Views.Public.class)List<User> result;//getters and setters
} 

Note
The @JsonView belongs to Jackson library, not Spring framework.

5.jQuery Ajax

在 JSP 中,创建一个简单的搜索表单,并用 jQuery $.ajax发送表单请求。

welcome.jsp

 <%@page session="false"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="en">
<head>
<c:url var="home" value="/" scope="request" /><spring:url value="/resources/core/css/hello.css" var="coreCss" />
<spring:url value="/resources/core/css/bootstrap.min.css"var="bootstrapCss" />
<link href="${bootstrapCss}" rel="stylesheet" />
<link href="${coreCss}" rel="stylesheet" /><spring:url value="/resources/core/js/jquery.1.10.2.min.js"var="jqueryJs" />
<script src="${jqueryJs}"></script>
</head><nav class="navbar navbar-inverse"><div class="container"><div class="navbar-header"><a class="navbar-brand" href="#">Spring 4 MVC Ajax Hello World</a></div></div>
</nav><div class="container" style="min-height: 500px"><div class="starter-template"><h1>Search Form</h1><br><div id="feedback"></div><form class="form-horizontal" id="search-form"><div class="form-group form-group-lg"><label class="col-sm-2 control-label">Username</label><div class="col-sm-10"><input type=text class="form-control" id="username"></div></div><div class="form-group form-group-lg"><label class="col-sm-2 control-label">Email</label><div class="col-sm-10"><input type="text" class="form-control" id="email"></div></div><div class="form-group"><div class="col-sm-offset-2 col-sm-10"><button type="submit" id="bth-search"class="btn btn-primary btn-lg">Search</button></div></div></form></div></div><div class="container"><footer><p>© <a href="http://www.mkyong.com">Mkyong.com</a> 2015</p></footer>
</div><script>jQuery(document).ready(function($) {$("#search-form").submit(function(event) {// Disble the search buttonenableSearchButton(false);// Prevent the form from submitting via the browser.event.preventDefault();searchViaAjax();});});function searchViaAjax() {var search = {}search["username"] = $("#username").val();search["email"] = $("#email").val();$.ajax({type : "POST",contentType : "application/json",url : "${home}search/api/getSearchResult",data : JSON.stringify(search),dataType : 'json',timeout : 100000,success : function(data) {console.log("SUCCESS: ", data);display(data);},error : function(e) {console.log("ERROR: ", e);display(e);},done : function(e) {console.log("DONE");enableSearchButton(true);}});}function enableSearchButton(flag) {$("#btn-search").prop("disabled", flag);}function display(data) {var json = "<h4>Ajax Response</h4><pre>"+ JSON.stringify(data, null, 4) + "</pre>";$('#feedback').html(json);}
</script></body>
</html> 

6.演示

6.1http://localhost:8080/spring 4 Ajax/

spring-mvc-ajax-example-demo-1

6.2 空字段验证。

spring-mvc-ajax-example-demo-2

6.3 按用户名搜索。

spring-mvc-ajax-example-demo-3

6.4.通过电子邮件搜索。

spring-mvc-ajax-example-demo-4

5.Chrome 浏览器,inspect 元素,网络标签。

spring-mvc-ajax-example-demo-5

7.这个项目怎么跑?

7.1 从 Github 克隆源代码

 $ git clone https://github.com/mkyong/spring4-mvc-ajax-example 

7.2 运行嵌入式码头容器。

 $ mvn jetty:run 

7.3 访问此 URL-http://localhost:8080/spring 4 Ajax/

下载源代码

Github link – spring4-mvc-maven-ajax-example.git

参考文献

  1. jQuery.ajax()
  2. 杰克逊专题:JSON 浏览量
  3. 通过 Spring MVC 使用@ JSON 视图
  4. 春天
  5. [ HTTP: status code definition
  6. Spring—@请求体
  7. Spring—@ response body
  8. 春天———

Spring AOP + AspectJ 注释示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-aop-aspectj-annotation-example/

在本教程中,我们将向您展示如何将 AspectJ 注释与 Spring AOP 框架集成。简单地说,Spring AOP + AspectJ 允许您轻松地拦截方法。

常见的 AspectJ 注释:

  1. @ Before–在方法执行前运行
  2. @ After–在方法返回结果后运行
  3. @ after returning–在方法返回结果后运行,同样截取返回结果。
  4. @ after throwing–在方法抛出异常后运行
  5. @ Around–围绕方法执行运行,结合以上三个建议。

Note
For Spring AOP without AspectJ support, read this build-in Spring AOP examples.

1.目录结构

请参见本示例的目录结构。

directory structure of this example

2.项目相关性

要启用 AspectJ,需要 aspectjrt.jaraspectjweaver.jarspring-aop.jar 。参见下面的 Maven pom.xml文件。

AspectJ supported since Spring 2.0
This example is using Spring 3, but the AspectJ features are supported since Spring 2.0.

文件:pom.xml

 <project ...><properties><spring.version>3.0.5.RELEASE</spring.version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><!-- Spring AOP + AspectJ --><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.6.11</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.6.11</version></dependency></dependencies>
</project> 

3.春豆

普通 bean 使用很少的方法,稍后通过 AspectJ 注释拦截它。

 package com.mkyong.customer.bo;public interface CustomerBo {void addCustomer();String addCustomerReturnValue();void addCustomerThrowException() throws Exception;void addCustomerAround(String name);
} 
 package com.mkyong.customer.bo.impl;import com.mkyong.customer.bo.CustomerBo;public class CustomerBoImpl implements CustomerBo {public void addCustomer(){System.out.println("addCustomer() is running ");}public String addCustomerReturnValue(){System.out.println("addCustomerReturnValue() is running ");return "abc";}public void addCustomerThrowException() throws Exception {System.out.println("addCustomerThrowException() is running ");throw new Exception("Generic Error");}public void addCustomerAround(String name){System.out.println("addCustomerAround() is running, args : " + name);}
} 

4.启用 AspectJ

在 Spring 配置文件中,放入“<aop:aspectj-autoproxy />”,定义你的方面(拦截器)和普通 bean。

文件:Spring-Customer.xml

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "><aop:aspectj-autoproxy /><bean id="customerBo" class="com.mkyong.customer.bo.impl.CustomerBoImpl" /><!-- Aspect --><bean id="logAspect" class="com.mkyong.aspect.LoggingAspect" /></beans> 

4.AspectJ @Before

在下面的例子中,logBefore()方法将在 customerBo 接口addCustomer()方法执行之前执行。

Note
AspectJ “pointcuts” is used to declare which method is going to intercept, and you should refer to this Spring AOP pointcuts guide for full list of supported pointcuts expressions.

文件:LoggingAspect.java

 package com.mkyong.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;@Aspect
public class LoggingAspect {@Before("execution(* com.mkyong.customer.bo.CustomerBo.addCustomer(..))")public void logBefore(JoinPoint joinPoint) {System.out.println("logBefore() is running!");System.out.println("hijacked : " + joinPoint.getSignature().getName());System.out.println("******");}} 

运行它

 CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");customer.addCustomer(); 

输出

 logBefore() is running!
hijacked : addCustomer
******
addCustomer() is running 

5.AspectJ @After

在下面的例子中,logAfter()方法将在 customerBo 接口addCustomer()方法执行之后执行。

文件:LoggingAspect.java

 package com.mkyong.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;@Aspect
public class LoggingAspect {@After("execution(* com.mkyong.customer.bo.CustomerBo.addCustomer(..))")public void logAfter(JoinPoint joinPoint) {System.out.println("logAfter() is running!");System.out.println("hijacked : " + joinPoint.getSignature().getName());System.out.println("******");}} 

运行它

 CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");customer.addCustomer(); 

输出

 addCustomer() is running 
logAfter() is running!
hijacked : addCustomer
****** 

6.AspectJ @AfterReturning

在下面的例子中,logAfterReturning()方法将在 customerBo 接口addCustomerReturnValue()方法执行之后执行。此外,可以用“返回属性拦截返回值。

要截取返回值,“returning”属性(result)的值需要与方法参数(result)相同。

文件:LoggingAspect.java

 package com.mkyong.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;@Aspect
public class LoggingAspect {@AfterReturning(pointcut = "execution(* com.mkyong.customer.bo.CustomerBo.addCustomerReturnValue(..))",returning= "result")public void logAfterReturning(JoinPoint joinPoint, Object result) {System.out.println("logAfterReturning() is running!");System.out.println("hijacked : " + joinPoint.getSignature().getName());System.out.println("Method returned value is : " + result);System.out.println("******");}} 

运行它

 CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");customer.addCustomerReturnValue(); 

输出

 addCustomerReturnValue() is running 
logAfterReturning() is running!
hijacked : addCustomerReturnValue
Method returned value is : abc
****** 

7.AspectJ @AfterReturning

在下面的例子中,如果 customerBo 接口,addCustomerThrowException()方法抛出异常,将执行logAfterThrowing()方法。

文件:LoggingAspect.java

 package com.mkyong.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;@Aspect
public class LoggingAspect {@AfterThrowing(pointcut = "execution(* com.mkyong.customer.bo.CustomerBo.addCustomerThrowException(..))",throwing= "error")public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {System.out.println("logAfterThrowing() is running!");System.out.println("hijacked : " + joinPoint.getSignature().getName());System.out.println("Exception : " + error);System.out.println("******");}
} 

运行它

 CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");customer.addCustomerThrowException(); 

输出

 addCustomerThrowException() is running 
logAfterThrowing() is running!
hijacked : addCustomerThrowException
Exception : java.lang.Exception: Generic Error
******
Exception in thread "main" java.lang.Exception: Generic Error//... 

8.AspectJ @Around

在下面的例子中,logAround()方法将在 customerBo 接口,addCustomerAround()方法之前执行,您必须定义“joinPoint.proceed();”来控制拦截器何时将控制返回给原始的addCustomerAround()方法。

文件:LoggingAspect.java

 package com.mkyong.aspect;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;@Aspect
public class LoggingAspect {@Around("execution(* com.mkyong.customer.bo.CustomerBo.addCustomerAround(..))")public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("logAround() is running!");System.out.println("hijacked method : " + joinPoint.getSignature().getName());System.out.println("hijacked arguments : " + Arrays.toString(joinPoint.getArgs()));System.out.println("Around before is running!");joinPoint.proceed(); //continue on the intercepted methodSystem.out.println("Around after is running!");System.out.println("******");}} 

运行它

 CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");customer.addCustomerAround("mkyong"); 

输出

 logAround() is running!
hijacked method : addCustomerAround
hijacked arguments : [mkyong]
Around before is running!
addCustomerAround() is running, args : mkyong
Around after is running!
****** 

结论

总是建议应用最小功率的 AsjectJ 注释。这是一篇关于春天的 AspectJ 的相当长的文章。有关进一步的解释和示例,请访问下面的参考链接。

Anti annotation or using JDK 1.4 ?
No worry, AspectJ supported XML configuration also, read this Spring AOP + AspectJ XML example.

下载源代码

Download it – Spring3-AOP-AspectJ-Example.zip (8 KB)

参考

  1. AspectJ 编程指南
  2. Spring AOP + AspectJ 引用

XML 配置示例中的 Spring AOP + AspectJ

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-aop-aspectj-in-xml-configuration-example/

在本教程中,我们将向您展示如何将最后的 Spring AOP + AspectJ 注释转换成基于 XML 的配置。

对于那些不喜欢注释或使用 JDK 1.4 的人,可以使用基于 XML 的 AspectJ。

再次回顾上一个 customerBo 接口,用几个方法,稍后你将学习如何通过 AspectJ 在 XML 文件中截取它。

 package com.mkyong.customer.bo;public interface CustomerBo {void addCustomer();String addCustomerReturnValue();void addCustomerThrowException() throws Exception;void addCustomerAround(String name);
} 

1.AspectJ= @之前

AspectJ @Before 示例。

 package com.mkyong.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;@Aspect
public class LoggingAspect {@Before("execution(* com.mkyong.customer.bo.CustomerBo.addCustomer(..))")public void logBefore(JoinPoint joinPoint) {//...}} 

XML 中的等效功能,用 < aop:在> 之前。

 <!-- Aspect -->
<bean id="logAspect" class="com.mkyong.aspect.LoggingAspect" /><aop:config><aop:aspect id="aspectLoggging" ref="logAspect" ><!-- @Before --><aop:pointcut id="pointCutBefore"expression="execution(* com.mkyong.customer.bo.CustomerBo.addCustomer(..))" /><aop:before method="logBefore" pointcut-ref="pointCutBefore" /></aop:aspect></aop:config> 

2.AspectJ = @After

AspectJ @After 示例。

 package com.mkyong.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;@Aspect
public class LoggingAspect {@After("execution(* com.mkyong.customer.bo.CustomerBo.addCustomer(..))")public void logAfter(JoinPoint joinPoint) {//...}} 

XML 中的等效功能,用**<:AOP:在>** 之后。

 <!-- Aspect -->
<bean id="logAspect" class="com.mkyong.aspect.LoggingAspect" /><aop:config><aop:aspect id="aspectLoggging" ref="logAspect" ><!-- @After --><aop:pointcut id="pointCutAfter"expression="execution(* com.mkyong.customer.bo.CustomerBo.addCustomer(..))" /><aop:after method="logAfter" pointcut-ref="pointCutAfter" /></aop:aspect></aop:config> 

3.AspectJ = @AfterReturning

AspectJ @AfterReturning 示例。

 package com.mkyong.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;@Aspect
public class LoggingAspect {@AfterReturning(pointcut = "execution(* com.mkyong.customer.bo.CustomerBo.addCustomerReturnValue(..))",returning= "result")public void logAfterReturning(JoinPoint joinPoint, Object result) {//...}} 

XML 中的等效功能,用 < aop:返回后>

 <!-- Aspect -->
<bean id="logAspect" class="com.mkyong.aspect.LoggingAspect" /><aop:config><aop:aspect id="aspectLoggging" ref="logAspect" ><!-- @AfterReturning --><aop:pointcut id="pointCutAfterReturning"expression="execution(* com.mkyong.customer.bo.CustomerBo.addCustomerReturnValue(..))" /><aop:after-returning method="logAfterReturning" returning="result" pointcut-ref="pointCutAfterReturning" /></aop:aspect></aop:config> 

4.AspectJ = @AfterReturning

AspectJ @AfterReturning 示例。

 package com.mkyong.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;@Aspect
public class LoggingAspect {@AfterThrowing(pointcut = "execution(* com.mkyong.customer.bo.CustomerBo.addCustomerThrowException(..))",throwing= "error")public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {//...}
} 

XML 中的等效功能,用 < aop:抛出后>

 <!-- Aspect -->
<bean id="logAspect" class="com.mkyong.aspect.LoggingAspect" /><aop:config><aop:aspect id="aspectLoggging" ref="logAspect" ><!-- @AfterThrowing --><aop:pointcut id="pointCutAfterThrowing"expression="execution(* com.mkyong.customer.bo.CustomerBo.addCustomerThrowException(..))" /><aop:after-throwing method="logAfterThrowing" throwing="error" pointcut-ref="pointCutAfterThrowing"  /></aop:aspect></aop:config> 

5.AspectJ= @左右

AspectJ @Around 示例。

 package com.mkyong.aspect;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;@Aspect
public class LoggingAspect {@Around("execution(* com.mkyong.customer.bo.CustomerBo.addCustomerAround(..))")public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {//...}} 

XML 中的等效功能,用 < aop:after-around >

 <!-- Aspect -->
<bean id="logAspect" class="com.mkyong.aspect.LoggingAspect" /><aop:config><aop:aspect id="aspectLoggging" ref="logAspect" ><!-- @Around --><aop:pointcut id="pointCutAround"expression="execution(* com.mkyong.customer.bo.CustomerBo.addCustomerAround(..))" /><aop:around method="logAround" pointcut-ref="pointCutAround"  /></aop:aspect></aop:config> 

完整的 XML 示例

参见完整的基于 AspectJ XML 的配置文件。

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "><aop:aspectj-autoproxy /><bean id="customerBo" class="com.mkyong.customer.bo.impl.CustomerBoImpl" /><!-- Aspect -->
<bean id="logAspect" class="com.mkyong.aspect.LoggingAspect" /><aop:config><aop:aspect id="aspectLoggging" ref="logAspect"><!-- @Before --><aop:pointcut id="pointCutBefore"expression="execution(* com.mkyong.customer.bo.CustomerBo.addCustomer(..))" /><aop:before method="logBefore" pointcut-ref="pointCutBefore" /><!-- @After --><aop:pointcut id="pointCutAfter"expression="execution(* com.mkyong.customer.bo.CustomerBo.addCustomer(..))" /><aop:after method="logAfter" pointcut-ref="pointCutAfter" /><!-- @AfterReturning --><aop:pointcut id="pointCutAfterReturning"expression="execution(* com.mkyong.customer.bo.CustomerBo.addCustomerReturnValue(..))" /><aop:after-returning method="logAfterReturning"returning="result" pointcut-ref="pointCutAfterReturning" /><!-- @AfterThrowing --><aop:pointcut id="pointCutAfterThrowing"expression="execution(* com.mkyong.customer.bo.CustomerBo.addCustomerThrowException(..))" /><aop:after-throwing method="logAfterThrowing"throwing="error" pointcut-ref="pointCutAfterThrowing" /><!-- @Around --><aop:pointcut id="pointCutAround"expression="execution(* com.mkyong.customer.bo.CustomerBo.addCustomerAround(..))" /><aop:around method="logAround" pointcut-ref="pointCutAround" /></aop:aspect></aop:config></beans> 

下载源代码

Download it – Spring3-AOP-AspectJ-XML-Example.zip (8 KB)

参考

  1. Spring AOP + AspectJ 注释示例
  2. AspectJ 编程指南
  3. Spring AOP + AspectJ 引用

aop aspectj spring

Spring AOP 错误:无法代理目标类,因为 CGLIB2 不可用

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-aop-error-cannot-proxy-target-class-because-cglib2-is-not-available/

在 Spring AOP 中,您必须将 cglib 库包含到您的构建路径中,以避免“无法代理目标类,因为 CGLIB2 不可用”错误消息。

 Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerServiceProxy': FactoryBean threw exception on object creation; nested exception is org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.at org.springframework.beans.factory.support.FactoryBeanRegistrySupport$1.run(FactoryBeanRegistrySupport.java:127)at java.security.AccessController.doPrivileged(Native Method)at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:116)at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:91)at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1288)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:217)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:880)at com.mkyong.common.App.main(App.java:14)
Caused by: org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.at org.springframework.aop.framework.DefaultAopProxyFactory.createAopProxy(DefaultAopProxyFactory.java:67)at org.springframework.aop.framework.ProxyCreatorSupport.createAopProxy(ProxyCreatorSupport.java:106)at org.springframework.aop.framework.ProxyFactoryBean.getSingletonInstance(ProxyFactoryBean.java:317)at org.springframework.aop.framework.ProxyFactoryBean.getObject(ProxyFactoryBean.java:243)at org.springframework.beans.factory.support.FactoryBeanRegistrySupport$1.run(FactoryBeanRegistrySupport.java:121)... 9 more 

解决办法

您可以从…下载 cglib 库

1.Cglib 官方网站
http://cglib.sourceforge.net/

2.美文库
http://repo1.maven.org/maven2/cglib/cglib/2.2/

如果您正在使用 Maven,您可以只包含 Maven 依赖项。

 <!-- AOP dependency --><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2</version></dependency> 

aop spring (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190216043613/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

Spring AOP 示例——切入点、顾问

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-aop-example-pointcut-advisor/

在最后一个 Spring AOP 建议示例中,一个类的所有方法都被自动拦截。但是在大多数情况下,你可能只需要一种方法来拦截一两个方法,这就是“切入点”的作用。它允许您通过方法名来截取方法。此外,“切入点”必须与“顾问”相关联。

在 Spring AOP 中,有三个非常专业的术语——advice,切入点,Advisor ,用非官方的方式来说…

  • 建议–指明在方法执行之前或之后要采取的行动。
  • 切入点——通过方法名或正则表达式模式指示应该截取哪个方法。
  • advisor——将“建议”和“切入点”组合成一个单元,并将其传递给代理工厂对象。

再次回顾上一个 Spring AOP 建议示例。

文件:CustomerService.java

 package com.mkyong.customer.services;public class CustomerService
{private String name;private String url;public void setName(String name) {this.name = name;}public void setUrl(String url) {this.url = url;}public void printName(){System.out.println("Customer name : " + this.name);}public void printURL(){System.out.println("Customer website : " + this.url);}public void printThrowException(){throw new IllegalArgumentException();}} 

文件:Spring-Customer.xml

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="customerService" class="com.mkyong.customer.services.CustomerService"><property name="name" value="Yong Mook Kim" /><property name="url" value="http://www.mkyong.com" /></bean><bean id="hijackAroundMethodBeanAdvice" class="com.mkyong.aop.HijackAroundMethod" /><bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="customerService" /><property name="interceptorNames"><list><value>hijackAroundMethodBeanAdvice</value></list></property></bean>
</beans> 

文件:HijackAroundMethod.java

 package com.mkyong.aop;import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;public class HijackAroundMethod implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {System.out.println("Method name : "+ methodInvocation.getMethod().getName());System.out.println("Method arguments : "+ Arrays.toString(methodInvocation.getArguments()));System.out.println("HijackAroundMethod : Before method hijacked!");try {Object result = methodInvocation.proceed();System.out.println("HijackAroundMethod : Before after hijacked!");return result;} catch (IllegalArgumentException e) {System.out.println("HijackAroundMethod : Throw exception hijacked!");throw e;}}
} 

运行它

 package com.mkyong.common;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.mkyong.customer.services.CustomerService;public class App {public static void main(String[] args) {ApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] { "Spring-Customer.xml" });CustomerService cust = (CustomerService) appContext.getBean("customerServiceProxy");System.out.println("*************************");cust.printName();System.out.println("*************************");cust.printURL();System.out.println("*************************");try {cust.printThrowException();} catch (Exception e) {}}
} 

输出

 *************************
Method name : printName
Method arguments : []
HijackAroundMethod : Before method hijacked!
Customer name : Yong Mook Kim
HijackAroundMethod : Before after hijacked!
*************************
Method name : printURL
Method arguments : []
HijackAroundMethod : Before method hijacked!
Customer website : http://www.mkyong.com
HijackAroundMethod : Before after hijacked!
*************************
Method name : printThrowException
Method arguments : []
HijackAroundMethod : Before method hijacked!
HijackAroundMethod : Throw exception hijacked! 

客户服务类的整个方法都被拦截。稍后,我们将向您展示如何使用“切入点来拦截 only printName()方法。

切入点示例

您可以通过以下两种方式匹配方法:

  1. 名称匹配
  2. 常规压制比赛

1.切入点——名称匹配示例

通过“切入点”和“顾问”截取 printName()方法。创建一个 NameMatchMethodPointcut 切入点 bean,并将您想要截取的方法名放入“ mappedName 属性值中。

 <bean id="customerPointcut"class="org.springframework.aop.support.NameMatchMethodPointcut"><property name="mappedName" value="printName" /></bean> 

创建一个DefaultPointcutAdvisoradvisor bean,并关联通知和切入点。

 <bean id="customerAdvisor"class="org.springframework.aop.support.DefaultPointcutAdvisor"><property name="pointcut" ref="customerPointcut" /><property name="advice" ref="hijackAroundMethodBeanAdvice" /></bean> 

将代理的“interceptorNames”替换为“customerAdvisor”(它是“hijackAroundMethodBeanAdvice”)。

 <bean id="customerServiceProxy"class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="customerService" /><property name="interceptorNames"><list><value>customerAdvisor</value></list></property></bean> 

完整的 bean 配置文件

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="customerService" class="com.mkyong.customer.services.CustomerService"><property name="name" value="Yong Mook Kim" /><property name="url" value="http://www.mkyong.com" /></bean><bean id="hijackAroundMethodBeanAdvice" class="com.mkyong.aop.HijackAroundMethod" /><bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="customerService" /><property name="interceptorNames"><list><value>customerAdvisor</value></list></property></bean><bean id="customerPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut"><property name="mappedName" value="printName" /></bean><bean id="customerAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"><property name="pointcut" ref="customerPointcut" /><property name="advice" ref="hijackAroundMethodBeanAdvice" /></bean></beans> 

再运行一次,输出

 *************************
Method name : printName
Method arguments : []
HijackAroundMethod : Before method hijacked!
Customer name : Yong Mook Kim
HijackAroundMethod : Before after hijacked!
*************************
Customer website : http://www.mkyong.com
************************* 

现在,您只拦截 printName()方法。

PointcutAdvisor
Spring comes with PointcutAdvisor class to save your work to declare advisor and pointcut into different beans, you can use NameMatchMethodPointcutAdvisor to combine both into a single bean.

 <bean id="customerAdvisor"class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"><property name="mappedName" value="printName" /><property name="advice" ref="hijackAroundMethodBeanAdvice" /></bean> 

2.切入点–正则表达式示例

您还可以通过使用正则表达式 pointcut–RegexpMethodPointcutAdvisor来匹配方法的名称。

 <bean id="customerAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><property name="patterns"><list><value>.*URL.*</value></list></property><property name="advice" ref="hijackAroundMethodBeanAdvice" /></bean> 

现在,它拦截方法名称中包含单词“URL”的方法。在实践中,你可以用它来管理 DAO 层,在这里你可以声明“”。道。 "拦截你所有的 DAO 类来支持事务。

下载源代码

Download it – Spring-AOP-Pointcuts-Advisor-Example.zipTags : aop spring

相关文章

  • Spring AOP 拦截器事务不工作

  • Spring AOP 错误:无法代理目标类,因为

  • Spring AOP 示例-建议

  • Spring AOP 在 Hibernate 中的事务管理

  • Spring AOP + AspectJ 注释示例

  • Spring AOP + AspectJ 在 XML 中的配置示例

  • Wicket + Spring 集成示例

  • Spring Autowiring @Qualifier 示例

  • Maven + Spring hello world 示例

  • 如何加载多个弹簧豆配置文件

Spring AOP 示例——建议

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-aop-examples-advice/

Spring AOP + AspectJ
Using AspectJ is more flexible and powerful, please refer to this tutorial – Using AspectJ annotation in Spring AOP.

Spring AOP ( 面向方面编程)框架用于模块化方面中的横切关注点。简单来说,它只是拦截某些进程的拦截器,比如当一个方法被执行时,Spring AOP 可以劫持正在执行的方法,并在方法执行之前或之后添加额外的功能。

在 Spring AOP 中,支持 4 种类型的建议:

  • 建议前–在方法执行前运行
  • 返回建议后–在方法返回结果后运行
  • 抛出建议后–在方法抛出异常后运行
  • 围绕建议——围绕方法执行,结合以上三个建议。

下面的例子向您展示了 Spring AOP 通知是如何工作的。

简单的弹簧示例

用几个打印方法创建一个简单的客户服务类,以便稍后演示。

 package com.mkyong.customer.services;public class CustomerService {private String name;private String url;public void setName(String name) {this.name = name;}public void setUrl(String url) {this.url = url;}public void printName() {System.out.println("Customer name : " + this.name);}public void printURL() {System.out.println("Customer website : " + this.url);}public void printThrowException() {throw new IllegalArgumentException();}} 

文件:Spring-customer . XML–一个 bean 配置文件

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="customerService" class="com.mkyong.customer.services.CustomerService"><property name="name" value="Yong Mook Kim" /><property name="url" value="http://www.mkyong.com" /></bean></beans> 

运行它

 package com.mkyong.common;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.mkyong.customer.services.CustomerService;public class App {public static void main(String[] args) {ApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] { "Spring-Customer.xml" });CustomerService cust = (CustomerService) appContext.getBean("customerService");System.out.println("*************************");cust.printName();System.out.println("*************************");cust.printURL();System.out.println("*************************");try {cust.printThrowException();} catch (Exception e) {}}
} 

输出

 *************************
Customer name : Yong Mook Kim
*************************
Customer website : http://www.mkyong.com
************************* 

一个简单的 Spring 项目到阿迪 bean 并输出一些字符串。

春季 AOP 建议

现在,将 Spring AOP 建议附加到上述客户服务中。

1.建议之前

它将在方法执行之前执行。创建一个实现 MethodBeforeAdvice 接口的类。

 package com.mkyong.aop;import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;public class HijackBeforeMethod implements MethodBeforeAdvice
{@Overridepublic void before(Method method, Object[] args, Object target)throws Throwable {System.out.println("HijackBeforeMethod : Before method hijacked!");}
} 

在 bean 配置文件(Spring-Customer.xml)中,为 HijackBeforeMethod 类创建一个 bean,并新建一个名为“ customerServiceProxy 的代理对象。

  • ‘target’–定义您想要劫持哪个 bean。
  • ‘interceptor names’–定义要在这个代理/目标对象上应用哪个类(通知)。
 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="customerService" class="com.mkyong.customer.services.CustomerService"><property name="name" value="Yong Mook Kim" /><property name="url" value="http://www.mkyong.com" /></bean><bean id="hijackBeforeMethodBean" class="com.mkyong.aop.HijackBeforeMethod" /><bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="customerService" /><property name="interceptorNames"><list><value>hijackBeforeMethodBean</value></list></property></bean>
</beans> 

Note
To use Spring proxy, you need to add CGLIB2 library. Add below in Maven pom.xml file.

 <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2.2</version></dependency> 

再次运行它,现在您得到了新的customerServiceProxybean,而不是原来的 customerService bean。

 package com.mkyong.common;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mkyong.customer.services.CustomerService;public class App {public static void main(String[] args) {ApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] { "Spring-Customer.xml" });CustomerService cust = (CustomerService) appContext.getBean("customerServiceProxy");System.out.println("*************************");cust.printName();System.out.println("*************************");cust.printURL();System.out.println("*************************");try {cust.printThrowException();} catch (Exception e) {}}
} 

输出

 *************************
HijackBeforeMethod : Before method hijacked!
Customer name : Yong Mook Kim
*************************
HijackBeforeMethod : Before method hijacked!
Customer website : http://www.mkyong.com
*************************
HijackBeforeMethod : Before method hijacked! 

在执行每个 customerService 的方法之前,它将运行 HijackBeforeMethod 的 before() 方法。

2.返回建议后

它将在方法返回结果后执行。创建一个在 ReturningAdvice 接口后实现的类。

 package com.mkyong.aop;import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;public class HijackAfterMethod implements AfterReturningAdvice
{@Overridepublic void afterReturning(Object returnValue, Method method,Object[] args, Object target) throws Throwable {System.out.println("HijackAfterMethod : After method hijacked!");}
} 

Bean 配置文件

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="customerService" class="com.mkyong.customer.services.CustomerService"><property name="name" value="Yong Mook Kim" /><property name="url" value="http://www.mkyong.com" /></bean><bean id="hijackAfterMethodBean" class="com.mkyong.aop.HijackAfterMethod" /><bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="customerService" /><property name="interceptorNames"><list><value>hijackAfterMethodBean</value></list></property></bean>
</beans> 

再运行一次,输出

 *************************
Customer name : Yong Mook Kim
HijackAfterMethod : After method hijacked!
*************************
Customer website : http://www.mkyong.com
HijackAfterMethod : After method hijacked!
************************* 

在返回结果的每个 customerService 的方法之后,它将运行 HijackAfterMethod 的 afterReturning() 方法。

3.抛出建议后

它将在方法引发异常后执行。创建一个实现 ThrowsAdvice 接口的类,创建一个 afterThrowing 方法劫持 IllegalArgumentException 异常。

 package com.mkyong.aop;import org.springframework.aop.ThrowsAdvice;public class HijackThrowException implements ThrowsAdvice {public void afterThrowing(IllegalArgumentException e) throws Throwable {System.out.println("HijackThrowException : Throw exception hijacked!");}
} 

Bean 配置文件

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="customerService" class="com.mkyong.customer.services.CustomerService"><property name="name" value="Yong Mook Kim" /><property name="url" value="http://www.mkyong.com" /></bean><bean id="hijackThrowExceptionBean" class="com.mkyong.aop.HijackThrowException" /><bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="customerService" /><property name="interceptorNames"><list><value>hijackThrowExceptionBean</value></list></property></bean>
</beans> 

再运行一次,输出

 *************************
Customer name : Yong Mook Kim
*************************
Customer website : http://www.mkyong.com
*************************
HijackThrowException : Throw exception hijacked! 

如果 customerService 的方法抛出异常,它将运行 HijackThrowException 的 afterThrowing() 方法。

4.围绕建议

它结合了上述所有三个建议,并在方法执行期间执行。创建一个实现 MethodInterceptor 接口的类。你要调用**" method invocation . proceed();**“继续原方法执行,否则原方法不会执行。

 package com.mkyong.aop;import java.util.Arrays;import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;public class HijackAroundMethod implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {System.out.println("Method name : "+ methodInvocation.getMethod().getName());System.out.println("Method arguments : "+ Arrays.toString(methodInvocation.getArguments()));// same with MethodBeforeAdviceSystem.out.println("HijackAroundMethod : Before method hijacked!");try {// proceed to original method callObject result = methodInvocation.proceed();// same with AfterReturningAdviceSystem.out.println("HijackAroundMethod : Before after hijacked!");return result;} catch (IllegalArgumentException e) {// same with ThrowsAdviceSystem.out.println("HijackAroundMethod : Throw exception hijacked!");throw e;}}
} 

Bean 配置文件

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="customerService" class="com.mkyong.customer.services.CustomerService"><property name="name" value="Yong Mook Kim" /><property name="url" value="http://www.mkyong.com" /></bean><bean id="hijackAroundMethodBean" class="com.mkyong.aop.HijackAroundMethod" /><bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="customerService" /><property name="interceptorNames"><list><value>hijackAroundMethodBean</value></list></property></bean>
</beans> 

再运行一次,输出

 *************************
Method name : printName
Method arguments : []
HijackAroundMethod : Before method hijacked!
Customer name : Yong Mook Kim
HijackAroundMethod : Before after hijacked!
*************************
Method name : printURL
Method arguments : []
HijackAroundMethod : Before method hijacked!
Customer website : http://www.mkyong.com
HijackAroundMethod : Before after hijacked!
*************************
Method name : printThrowException
Method arguments : []
HijackAroundMethod : Before method hijacked!
HijackAroundMethod : Throw exception hijacked! 

在每个 customerService 的方法执行之后,它将运行 HijackAroundMethod 的 invoke() 方法。

结论

大多数 Spring 开发者只是实现了‘Around advice ’,因为它可以应用所有的建议类型,但是更好的实践应该选择最合适的建议类型来满足需求。

Pointcut
In this example, all the methods in a customer service class are intercepted (advice) automatically. But for most cases, you may need to use Pointcut and Advisor to intercept a method via it’s method name.

下载源代码

Download it – Spring-AOP-Advice-Examples.zip (8 KB)aop spring

Spring AOP 拦截器事务不工作

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-aop-interceptor-transaction-is-not-working/

问题

Spring AOP 事务在下列拦截器中不起作用?

 <bean id="testAutoProxyCreator"class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><property name="interceptorNames"><list><idref bean="urlInterceptorInsert" /><idref bean="urlInterceptorCommit" /><idref bean="urlInterceptorRelease" /><idref bean="matchGenericTxInterceptor" /></list></property><property name="beanNames"><list><idref local="urlBo" /></list></property>
</bean> 

matchgenericxinterceptor”事务拦截器,本应该拦截urlInterceptorInserturlInterceptorCommiturlInterceptorRelease,但是没有按预期工作?

解决办法

这 3 个拦截器在事务管理器拦截器(matchgenericxinterceptor)之前执行。

要解决这个问题,您必须改变拦截器 xml 文件的顺序,如下所示(将matchGenericTxInterceptor放在顶部)。

 <bean id="testAutoProxyCreator"class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><property name="interceptorNames"><list><idref bean="matchGenericTxInterceptor" /><idref bean="urlInterceptorInsert" /><idref bean="urlInterceptorCommit" /><idref bean="urlInterceptorRelease" /></list></property><property name="beanNames"><list><idref local="urlBo" /></list></property>
</bean> 

Note
The sequence of Spring AOP interceptors do affect the functionality.Tags : aop spring

Hibernate 中的 Spring AOP 事务管理

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-aop-transaction-management-in-hibernate/

需要事务管理来保证数据库中数据的完整性和一致性。Spring 的 AOP 技术允许开发者声明性地管理事务。

下面的例子展示了如何用 Spring AOP 管理 Hibernate 事务。

P.S 很多 Hibernate 和 Spring 的配置文件都是隐藏的,只显示了一些重要的文件,如果你想亲自动手,可以在文末下载完整的项目。

1.表格创建

MySQL 表脚本,一个产品表和一个产品现存量表。

 CREATE TABLE  `mkyong`.`product` (`PRODUCT_ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,`PRODUCT_CODE` varchar(20) NOT NULL,`PRODUCT_DESC` varchar(255) NOT NULL,PRIMARY KEY (`PRODUCT_ID`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE TABLE  `mkyong`.`product_qoh` (`QOH_ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,`PRODUCT_ID` bigint(20) unsigned NOT NULL,`QTY` int(10) unsigned NOT NULL,PRIMARY KEY (`QOH_ID`),KEY `FK_product_qoh_product_id` (`PRODUCT_ID`),CONSTRAINT `FK_product_qoh_product_id` FOREIGN KEY (`PRODUCT_ID`) REFERENCES `product` (`PRODUCT_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; 

2.产品业务对象

在这个' productBo '实现中, save() 方法将通过 'productDao '类向' product 表中插入一条记录,并通过' productQohBo '类向' productQoh 表中插入一条现有量记录。

 package com.mkyong.product.bo.impl;import com.mkyong.product.bo.ProductBo;
import com.mkyong.product.bo.ProductQohBo;
import com.mkyong.product.dao.ProductDao;
import com.mkyong.product.model.Product;
import com.mkyong.product.model.ProductQoh;public class ProductBoImpl implements ProductBo{ProductDao productDao;ProductQohBo productQohBo;public void setProductDao(ProductDao productDao) {this.productDao = productDao;}public void setProductQohBo(ProductQohBo productQohBo) {this.productQohBo = productQohBo;}//this method need to be transactionalpublic void save(Product product, int qoh){productDao.save(product);System.out.println("Product Inserted");ProductQoh productQoh = new ProductQoh();productQoh.setProductId(product.getProductId());productQoh.setQty(qoh);productQohBo.save(productQoh);System.out.println("ProductQoh Inserted");}
} 

Spring 的 bean 配置文件。

 <!-- Product business object --><bean id="productBo" class="com.mkyong.product.bo.impl.ProductBoImpl" ><property name="productDao" ref="productDao" /><property name="productQohBo" ref="productQohBo" /></bean><!-- Product Data Access Object --><bean id="productDao" class="com.mkyong.product.dao.impl.ProductDaoImpl" ><property name="sessionFactory" ref="sessionFactory"></property></bean> 

运行它

 Product product = new Product();product.setProductCode("ABC");product.setProductDesc("This is product ABC");ProductBo productBo = (ProductBo)appContext.getBean("productBo");productBo.save(product, 100); 

假设 save() 不具有事务特性,如果 productQohBo.save() 抛出异常,您将只在' product 表中插入一条记录,而不会在' productQoh 表中插入任何记录。这是一个严重的问题,会破坏数据库中的数据一致性。

3.事务管理

为 Hibernate 事务声明了一个'transaction interceptorbean 和一个'Hibernate transaction manager,并传递了必要的属性。

 <beans 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"><property name="transactionManager" ref="transactionManager" /><property name="transactionAttributes"><props><prop key="save">PROPAGATION_REQUIRED</prop></props></property></bean><bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="dataSource" ref="dataSource" /><property name="sessionFactory" ref="sessionFactory" /></bean></beans> 
交易属性

在事务拦截器中,您必须定义应该使用哪个事务属性'传播行为。意思是如果一个事务性的 'ProductBoImpl.save() '方法被另一个方法' productQohBo.save() '调用,那么事务应该如何传播?它应该继续在现有事务中运行吗?或者为它自己开始新的事务。

Spring 支持 7 种类型的传播:

  • PROPAGATION _ REQUIRED–支持当前交易;如果不存在,请创建一个新的。
  • PROPAGATION _ SUPPORTS–支持当前交易;如果不存在,则以非事务方式执行。
  • PROPAGATION _ MANDATORY–支持当前交易;如果不存在当前事务,则引发异常。
  • PROPAGATION _ REQUIRES _ NEW–创建新事务,如果当前事务存在,则暂停当前事务。
  • PROPAGATION _ NOT _ SUPPORTED–不支持当前事务;而是总是以非事务方式执行。
  • PROPAGATION _ NEVER–不支持当前交易;如果当前事务存在,则引发异常。
  • PROPAGATION _ NESTED–如果当前事务存在,则在嵌套事务中执行,类似于 PROPAGATION_REQUIRED else。

在大多数情况下,您可能只需要使用 PROPAGATION_REQUIRED。

此外,您还必须定义方法来支持这个事务属性。方法名支持通配符格式,一个 save* 将匹配所有以 save(…)开头的方法名。

事务管理程序

在 Hibernate 事务中,需要使用HibernateTransactionManager。如果只处理纯 JDBC,使用DataSourceTransactionManager;而 JTA 则使用 JtaTransactionManager

4.代理工厂 Bean

ProductBo 创建一个新的代理工厂 bean,并设置“拦截器名称属性。

 <!-- Product business object --><bean id="productBo" class="com.mkyong.product.bo.impl.ProductBoImpl" ><property name="productDao" ref="productDao" /><property name="productQohBo" ref="productQohBo" /></bean><!-- Product Data Access Object --><bean id="productDao" class="com.mkyong.product.dao.impl.ProductDaoImpl" ><property name="sessionFactory" ref="sessionFactory"></property></bean><bean id="productBoProxy"class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="productBo" /><property name="interceptorNames"><list><value>transactionInterceptor</value></list></property></bean> 

运行它

 Product product = new Product();product.setProductCode("ABC");product.setProductDesc("This is product ABC");ProductBo productBo = (ProductBo)appContext.getBean("productBoProxy");productBo.save(product, 100); 

获取您的代理 bean ' productBoProxy ',并且您的 save() 方法现在支持事务性,在 productBo.save() 方法中的任何异常都将导致整个事务回滚,不会有数据插入数据库。

下载源代码

Download it – Spring-Hibernate-Transaction-Example.zip

参考

  1. http://static . springsource . org/spring/docs/2.5 . x/API/org/spring framework/transaction/transaction definition . html
  2. http://static . springsource . org/spring/docs/2.5 . x/reference/transaction . html

Spring 自动代理创建器示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-auto-proxy-creator-example/

在去年春天的 AOP 示例中——advice、 pointcut 和 advisor ,您必须为每个需要 AOP 支持的 bean 手工创建一个代理 bean (ProxyFactoryBean)。

这不是一种有效的方式,例如,如果您希望 customer 模块中的所有 DAO 类都实现带有 SQL 日志支持(advise)的 AOP 特性,那么您必须手动创建许多代理工厂 bean,结果是您的 bean 配置文件中充斥了大量的代理 bean。

幸运的是,Spring 附带了两个自动代理创建器来自动为您的 beans 创建代理。

1.BeanNameAutoProxyCreator 示例

在此之前,您必须手动创建一个代理 bean (ProxyFactoryBean)。

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="customerService" class="com.mkyong.customer.services.CustomerService"><property name="name" value="Yong Mook Kim" /><property name="url" value="http://www.mkyong.com" /></bean><bean id="hijackAroundMethodBeanAdvice" class="com.mkyong.aop.HijackAroundMethod" /><bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="customerService" /><property name="interceptorNames"><list><value>customerAdvisor</value></list></property></bean><bean id="customerAdvisor"class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"><property name="mappedName" value="printName" /><property name="advice" ref="hijackAroundMethodBeanAdvice" /></bean>
</beans> 

并获取代理名为“customerServiceProxy”的 bean。

 CustomerService cust = (CustomerService)appContext.getBean("customerServiceProxy"); 

在自动代理机制中,您只需要创建一个 BeanNameAutoProxyCreator ,并将您的所有 bean(通过 bean 名称或正则表达式名称)和“advisor”包含到一个单元中。

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="customerService" class="com.mkyong.customer.services.CustomerService"><property name="name" value="Yong Mook Kim" /><property name="url" value="http://www.mkyong.com" /></bean><bean id="hijackAroundMethodBeanAdvice" class="com.mkyong.aop.HijackAroundMethod" /><bean id="customerAdvisor"class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"><property name="mappedName" value="printName" /><property name="advice" ref="hijackAroundMethodBeanAdvice" /></bean><beanclass="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><property name="beanNames"><list><value>*Service</value></list></property><property name="interceptorNames"><list><value>customerAdvisor</value></list></property></bean>
</beans> 

现在,您可以通过原始名称“customerService”获得 bean,您甚至不知道这个 bean 已经被代理。

 CustomerService cust = (CustomerService)appContext.getBean("customerService"); 

2.DefaultAdvisorAutoProxyCreator 示例

这个DefaultAdvisorAutoProxyCreator非常强大,如果任何一个 beans 被 advisor 匹配,Spring 将自动为它创建一个代理。

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="customerService" class="com.mkyong.customer.services.CustomerService"><property name="name" value="Yong Mook Kim" /><property name="url" value="http://www.mkyong.com" /></bean><bean id="hijackAroundMethodBeanAdvice" class="com.mkyong.aop.HijackAroundMethod" /><bean id="customerAdvisor"class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"><property name="mappedName" value="printName" /><property name="advice" ref="hijackAroundMethodBeanAdvice" /></bean><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" /></beans> 

这只是越权,因为你不能控制 bean 应该代理什么,你能做的只是相信 Spring 会为你做得最好。如果你想在你的项目中实现它,请小心。

下载源代码

Download it – Spring-Auto-Proxy-Creator-Example.zipproxy spring

Spring 自动布线 Beans

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-auto-wiring-beans-in-xml/

在 Spring framework 中,您可以使用自动连接特性自动连接 beans。要启用它,只需在< bean >中定义“自动连线属性。

 <bean id="customer" class="com.mkyong.common.Customer" autowire="byName" /> 

在 Spring 中,支持 5 种自动布线模式。

  • 否–默认,无自动布线,通过“ref”属性手动设置
  • 按名称–按属性名称自动布线。如果一个 bean 的名称与其他 bean 属性的名称相同,则自动连接它。
  • byType–按属性数据类型自动连接。如果一个 bean 的数据类型与其他 bean 属性的数据类型兼容,则自动连接它。
  • constructor–构造函数参数中的 byType 模式。
  • 自动检测–如果找到默认的构造函数,使用“由构造函数自动连接”;否则,使用“按类型自动关联”。

例子

用于自动布线演示的客户和人员对象。

 package com.mkyong.common;public class Customer 
{private Person person;public Customer(Person person) {this.person = person;}public void setPerson(Person person) {this.person = person;}//...
} 
 package com.mkyong.common;public class Person 
{//...
} 

1.自动布线'否'

这是默认模式,您需要通过“ref”属性连接您的 bean。

 <bean id="customer" class="com.mkyong.common.Customer"><property name="person" ref="person" /></bean><bean id="person" class="com.mkyong.common.Person" /> 

2.自动布线'按名称'

通过属性名自动连接 bean。在这种情况下,由于“person”bean 的名称与“customer”bean 的属性名称(“person”)相同,因此,Spring 将通过 setter 方法自动连接它—“setPerson(Person person)”。

 <bean id="customer" class="com.mkyong.common.Customer" autowire="byName" /><bean id="person" class="com.mkyong.common.Person" /> 

参见完整示例-名为的弹簧自动布线。

3.自动布线'按类型'

通过属性数据类型自动连接 bean。在这种情况下,由于“person”bean 的数据类型与“customer”bean 的属性(Person 对象)的数据类型相同,所以 Spring 将通过 setter 方法自动连接它。

 <bean id="customer" class="com.mkyong.common.Customer" autowire="byType" /><bean id="person" class="com.mkyong.common.Person" /> 

参见完整示例-按类型进行弹簧自动布线。

4.自动布线'构造器'

通过构造函数参数中的属性数据类型自动连接 bean。在这种情况下,由于“person”bean 的数据类型与“customer”bean 的属性(Person 对象)中的构造函数参数数据类型相同,因此,Spring 通过构造函数方法——“public Customer(Person person)”自动连接它。

 <bean id="customer" class="com.mkyong.common.Customer" autowire="constructor" /><bean id="person" class="com.mkyong.common.Person" /> 

参见完整示例-由构造者进行弹簧自动布线。

5.自动布线'自动检测'

如果找到默认构造函数,则使用“构造函数”;否则,使用“byType”。在这种情况下,由于“Customer”类中有一个默认的构造函数,所以 Spring 通过构造函数方法-“public Customer(Person person)”自动连接它。

 <bean id="customer" class="com.mkyong.common.Customer" autowire="autodetect" /><bean id="person" class="com.mkyong.common.Person" /> 

参见完整示例-通过自动检测触发自动布线。

Note
It’s always good to combine both ‘auto-wire’ and ‘dependency-check’ together, to make sure the property is always auto-wire successfully.

 <bean id="customer" class="com.mkyong.common.Customer" autowire="autodetect" dependency-check="objects /><bean id="person" class="com.mkyong.common.Person" /> 

结论

在我看来,Spring 的“自动连接”以巨大的代价加快了开发速度——它增加了整个 bean 配置文件的复杂性,你甚至不知道哪个 bean 将自动连接到哪个 bean 中。

在实践中,我宁愿手动连线,它总是很干净,工作很完美,或者更好地使用 @Autowired annotation ,这更灵活,也更值得推荐。

spring wiring

带有@Autowired 注释的 Spring 自动连接 Beans

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-auto-wiring-beans-with-autowired-annotation/

在 XML 的最后一个 Spring 自动连接示例中,它将自动连接当前 Spring 容器中任何 bean 的匹配属性。在大多数情况下,您可能只需要特定 bean 中的 autowired 属性。

在 Spring 中,您可以使用 @Autowired 注释来自动连接 setter 方法、构造函数或字段上的 bean。此外,它可以自动连接特定 bean 中的属性。

Note
The @Autowired annotation is auto wire the bean by matching data type.

参见下面的完整示例,演示如何使用**@自动连线**。

1.豆子

一个客户 bean,并在 bean 配置文件中声明。稍后,您将使用“ @Autowired ”来自动连接一个人 bean。

 package com.mkyong.common;public class Customer 
{//you want autowired this field.private Person person;private int type;private String action;//getter and setter method} 
 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="CustomerBean" class="com.mkyong.common.Customer"><property name="action" value="buy" /><property name="type" value="1" /></bean><bean id="PersonBean" class="com.mkyong.common.Person"><property name="name" value="mkyong" /><property name="address" value="address 123" /><property name="age" value="28" /></bean></beans> 

2.注册 AutowiredAnnotationBeanPostProcessor

要启用 @Autowired ,需要注册“AutowiredAnnotationBeanPostProcessor”,有两种方式:

1.包括

在 bean 配置文件中添加 Spring 上下文和。

 <beans //...xmlns:context="http://www.springframework.org/schema/context"//...http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd">//...<context:annotation-config />//...
</beans> 

完整示例,

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd"><context:annotation-config /><bean id="CustomerBean" class="com.mkyong.common.Customer"><property name="action" value="buy" /><property name="type" value="1" /></bean><bean id="PersonBean" class="com.mkyong.common.Person"><property name="name" value="mkyong" /><property name="address" value="address ABC" /><property name="age" value="29" /></bean></beans> 
2.包括 AutowiredAnnotationBeanPostProcessor

将“AutowiredAnnotationBeanPostProcessor”直接包含在 bean 配置文件中。

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean 
class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/><bean id="CustomerBean" class="com.mkyong.common.Customer"><property name="action" value="buy" /><property name="type" value="1" /></bean><bean id="PersonBean" class="com.mkyong.common.Person"><property name="name" value="mkyong" /><property name="address" value="address ABC" /><property name="age" value="29" /></bean></beans> 

3.@自动连线示例

现在,您可以通过 @Autowired 自动连接 bean,它可以应用于 setter 方法、构造函数或字段。

1.@Autowired setter 方法
 package com.mkyong.common;import org.springframework.beans.factory.annotation.Autowired;public class Customer 
{private Person person;private int type;private String action;//getter and setter methods@Autowiredpublic void setPerson(Person person) {this.person = person;}
} 
2.@autowired 构造函数
 package com.mkyong.common;import org.springframework.beans.factory.annotation.Autowired;public class Customer 
{private Person person;private int type;private String action;//getter and setter methods@Autowiredpublic Customer(Person person) {this.person = person;}
} 
3.@自动连线字段
 package com.mkyong.common;import org.springframework.beans.factory.annotation.Autowired;public class Customer 
{@Autowiredprivate Person person;private int type;private String action;//getter and setter methods
} 

上面的示例将“PersonBean”自动连接到客户的个人属性中。

运行它

 package com.mkyong.common;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App 
{public static void main( String[] args ){ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"SpringBeans.xml"});Customer cust = (Customer)context.getBean("CustomerBean");System.out.println(cust);}
} 

输出

 Customer [action=buy, type=1, 
person=Person [address=address 123, age=28, name=mkyong]] 

依赖性检查

默认情况下,@Autowired 将执行依赖项检查,以确保属性已正确连接。当 Spring 找不到匹配的 bean 来连接时,它会抛出一个异常。要解决这个问题,可以通过将@Autowired 的“ required ”属性设置为 false 来禁用这个检查特性。

 package com.mkyong.common;import org.springframework.beans.factory.annotation.Autowired;public class Customer 
{@Autowired(required=false)private Person person;private int type;private String action;//getter and setter methods
} 

在上面的例子中,如果 Spring 找不到匹配的 bean,它将保留 person 属性不变。

@限定符

@Qualifier 注释用于控制应该在字段上自动连接哪个 bean。例如,bean 配置文件包含两个相似的 person beans。

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd"><context:annotation-config /><bean id="CustomerBean" class="com.mkyong.common.Customer"><property name="action" value="buy" /><property name="type" value="1" /></bean><bean id="PersonBean1" class="com.mkyong.common.Person"><property name="name" value="mkyong1" /><property name="address" value="address 1" /><property name="age" value="28" /></bean><bean id="PersonBean2" class="com.mkyong.common.Person"><property name="name" value="mkyong2" /><property name="address" value="address 2" /><property name="age" value="28" /></bean></beans> 

Spring 会知道应该给哪个 bean 布线吗?

要解决这个问题,您可以使用 @Qualifier 来自动连接特定的 bean,例如,

 package com.mkyong.common;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;public class Customer 
{@Autowired@Qualifier("PersonBean1")private Person person;private int type;private String action;//getter and setter methods
} 

这意味着,bean“person bean 1”被自动绑定到客户的个人属性中。阅读完整示例—Spring auto wiring @ Qualifier 示例

结论

这个 @Autowired 注释高度灵活且功能强大,绝对优于 bean 配置文件中的“ autowire ”属性。

下载源代码

Download It – Spring-Autowired-Annotation-Example.zip (6 KB)Tags : spring wiring

通过自动检测进行弹簧自动布线

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-autowiring-by-autodetect/

在 Spring 中,“ Autowiring by AutoDetect ”表示如果默认构造函数(带任何数据类型的参数),则选择“ autowire by constructor ”,否则使用“ autowire by type ”。

参见 Spring“通过自动检测进行自动布线”的示例。通过构造函数或类型将“功夫”bean 自动连接到“熊猫”中(基于熊猫 bean 的实现)。

 <bean id="panda" class="com.mkyong.common.Panda" autowire="autodetect" /><bean id="kungfu" class="com.mkyong.common.KungFu" ><property name="name" value="Shao lin" /></bean> 

1.自动检测–由构造函数

如果提供了默认构造器,自动检测将按构造器选择焊线。

 package com.mkyong.common;public class Panda {private KungFu kungfu;public Panda(KungFu kungfu) {System.out.println("autowiring by constructor");this.kungfu = kungfu;}public KungFu getKungfu() {return kungfu;}public void setKungfu(KungFu kungfu) {System.out.println("autowiring by type");this.kungfu = kungfu;}//...
} 

输出

 autowiring by constructor
Person [kungfu=Language [name=Shao lin]] 

2.自动检测–按类型

如果没有找到默认构造函数,自动检测将按类型选择焊线。

 package com.mkyong.common;public class Panda {private KungFu kungfu;public KungFu getKungfu() {return kungfu;}public void setKungfu(KungFu kungfu) {System.out.println("autowiring by type");this.kungfu = kungfu;}//...
} 

输出

 autowiring by type
Person [kungfu=Language [name=Shao lin]] 

下载源代码

Download it – Spring-AutoWiring-by-Auto-Detect-Example.zip (6 KB)

参考

  1. 弹簧按类型自动布线
  2. 弹簧由构造者自动接线

spring wiring

由构造者进行弹簧自动布线

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-autowiring-by-constructor/

在 Spring 中,“由构造器自动连线”实际上是由构造器参数中的类型自动连线。这意味着,如果一个 bean 的数据类型与另一个 bean 构造函数参数的数据类型相同,就自动连接它。

查看构造函数的 Spring 自动布线的完整示例。

1.豆子

两个豆子,开发者和语言。

 package com.mkyong.common;public class Developer {private Language language;//autowire by constructorpublic Developer(Language language) {this.language = language;}//...} 
 package com.mkyong.common;public class Language {private String name;//...
} 

2.弹簧布线

通常,通过构造函数连接 bean,如下所示:

 <bean id="developer" class="com.mkyong.common.Developer"><constructor-arg><ref bean="language" /></constructor-arg></bean><bean id="language" class="com.mkyong.common.Language" ><property name="name" value="Java" /></bean> 

输出

 Developer [language=Language [name=Java]] 

启用通过构造器自动连线后,可以不设置构造器属性。Spring 会找到兼容的数据类型并自动连接它。

 <bean id="developer" class="com.mkyong.common.Developer" autowire="constructor" /><bean id="language" class="com.mkyong.common.Language" ><property name="name" value="Java" /></bean> 

输出

 Developer [language=Language [name=Java]] 

下载源代码

Download it – Spring-AutoWiring-by-Constructor-Example.zip (6 KB)

参考

  1. Spring DI 通过构造器
  2. 弹簧按类型自动布线

spring wiring

弹簧按名称自动布线

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-autowiring-by-name/

在 Spring 中,“按名称自动连接”意味着,如果一个 bean 的名称与其他 bean 属性的名称相同,就自动连接它。

例如,如果一个“客户”bean 公开了一个“地址”属性,Spring 将在当前容器中找到“地址”bean 并自动连接它。如果没有找到匹配,就什么都不做。

您可以通过autowire="byName"启用该功能,如下所示:

 <!-- customer has a property name "address" --><bean id="customer" class="com.mkyong.common.Customer" autowire="byName" /><bean id="address" class="com.mkyong.common.Address" ><property name="fulladdress" value="Block A 888, CA" /></bean> 

按名称查看 Spring 自动布线的完整示例。

1.豆子

两个 beans,客户和地址。

 package com.mkyong.common;public class Customer 
{private Address address;//...
} 
 package com.mkyong.common;public class Address 
{private String fulladdress;//...
} 

2.弹簧布线

通常,通过 ref 属性显式连接 bean,如下所示:

 <bean id="customer" class="com.mkyong.common.Customer" ><property name="address" ref="address" /></bean><bean id="address" class="com.mkyong.common.Address" ><property name="fulladdress" value="Block A 888, CA" /></bean> 

输出

 Customer [address=Address [fulladdress=Block A 888, CA]] 

启用了auto wire by name后,您不再需要声明属性标签。只要“地址”bean 与“客户”bean 的属性“地址”同名,Spring 就会自动连接它。

 <bean id="customer" class="com.mkyong.common.Customer" autowire="byName" /><bean id="address" class="com.mkyong.common.Address" ><property name="fulladdress" value="Block A 888, CA" /></bean> 

输出

 Customer [address=Address [fulladdress=Block A 888, CA]] 

再看另一个例子,这一次,连线会失败,导致 bean“address ABC”与 bean“customer”的属性名不匹配。

 <bean id="customer" class="com.mkyong.common.Customer" autowire="byName" /><bean id="addressABC" class="com.mkyong.common.Address" ><property name="fulladdress" value="Block A 888, CA" /></bean> 

输出

 Customer [address=null] 

下载源代码

Download it – Spring-AutoWiring-by-Name-Example.zip (6 KB)spring wiring

按类型排列的弹簧自动布线

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-autowiring-by-type/

在 Spring 中,“按类型自动连接”意味着,如果一个 bean 的数据类型与其他 bean 属性的数据类型兼容,就自动连接它。

例如,一个“person”bean 公开了一个数据类型为“capability”类的属性,Spring 将找到数据类型为“capability”类的 bean,并自动连接它。如果没有找到匹配,就什么都不做。

您可以通过autowire="byType"启用该功能,如下所示:

 <!-- person has a property type of class "ability" --><bean id="person" class="com.mkyong.common.Person" autowire="byType" /><bean id="invisible" class="com.mkyong.common.Ability" ><property name="skill" value="Invisible" /></bean> 

按类型查看 Spring 自动布线的完整示例。

1.豆子

两颗豆子,人和能力。

 package com.mkyong.common;public class Person 
{private Ability ability;//...
} 
 package com.mkyong.common;public class Ability 
{private String skill;//...
} 

2.弹簧布线

通常,您显式连接 bean:

 <bean id="person" class="com.mkyong.common.Person"><property name="ability" ref="invisible" /></bean><bean id="invisible" class="com.mkyong.common.Ability" ><property name="skill" value="Invisible" /></bean> 

输出

 Person [ability=Ability [skill=Invisible]] 

启用自动按类型连线后,您可以不设置能力属性。Spring 将找到相同的数据类型并自动连接它。

 <bean id="person" class="com.mkyong.common.Person" autowire="byType" /><bean id="invisible" class="com.mkyong.common.Ability" ><property name="skill" value="Invisible" /></bean> 

输出

 Person [ability=Ability [skill=Invisible]] 

等等,如果你有两个数据类型相同的类“能力”的 beans 呢?

 <bean id="person" class="com.mkyong.common.Person" autowire="byType" /><bean id="steal" class="com.mkyong.common.Ability" ><property name="skill" value="Steal" /></bean><bean id="invisible" class="com.mkyong.common.Ability" ><property name="skill" value="Invisible" /></bean> 

输出

 Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: 
...
No unique bean of type [com.mkyong.common.Ability] is defined: 
expected single matching bean but found 2: [steal, invisible]; nested exception is 
org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No unique bean of type [com.mkyong.common.Ability] is defined: 
expected single matching bean but found 2: [steal, invisible] 

在这种情况下,你会点击UnsatisfiedDependencyException错误信息。

Note
In autowiring by type mode, you just have to make sure only one unique data type of bean is declared. ## 下载源代码

Download it – Spring-AutoWiring-by-Type-Example.zip (6 KB)spring wiring

Spring 自动布线@Qualifier 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-autowiring-qualifier-example/

在 Spring 中,@Qualifier 表示哪个 bean 有资格在字段上自动绑定。请参见以下场景:

自动布线示例

参见下面的例子,它将一个“person”bean 自动连接到客户的 person 属性中。

 package com.mkyong.common;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;public class Customer {@Autowiredprivate Person person;//...
} 

但是,在 bean 配置文件中声明了两个相似的 bean“com.mkyong.common.Person”。Spring 会知道应该自动连线哪个人 bean 吗?

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean 
class ="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/><bean id="customer" class="com.mkyong.common.Customer" /><bean id="personA" class="com.mkyong.common.Person" ><property name="name" value="mkyongA" /></bean><bean id="personB" class="com.mkyong.common.Person" ><property name="name" value="mkyongB" /></bean></beans> 

当您运行以上示例时,会遇到以下异常:

 Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.mkyong.common.Person] is defined: expected single matching bean but found 2: [personA, personB] 

@限定符示例

要解决上述问题,您需要 @Quanlifier 告诉 Spring 应该自动连接哪个 bean。

 package com.mkyong.common;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;public class Customer {@Autowired@Qualifier("personA")private Person person;//...
} 

在这种情况下,bean“personA”是自动连接的。

 Customer [person=Person [name=mkyongA]] 

下载源代码

Download It – Spring-AutoWiring-Qualifier-Example.zip (6 KB)

参考

  1. Spring @Autowired 示例

spring wiring

Spring Batch:作业实例已经存在,并且对于参数=

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-batch/spring-batch-a-job-instance-already-exists-and-is-complete-for-parameters/

使用 Spring Batch 2.2.0.RELEASE,并使用 Spring Scheduler 启动作业。

CustomJobLauncher.java

 package com.mkyong.batch;import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class CustomJobLauncher {@AutowiredJobLauncher jobLauncher;@AutowiredJob job;public void run() {try {JobExecution execution = jobLauncher.run(job, new JobParameters());System.out.println("Exit Status : " + execution.getStatus());} catch (Exception e) {e.printStackTrace();}}} 

job-config.xml

 <bean id="customJobLauncher" class="com.mkyong.batch.CustomJobLauncher" /><task:scheduled-tasks><task:scheduled ref="customJobLauncher" method="run" fixed-delay="10000" /></task:scheduled-tasks> 

问题

批处理作业仅在第一次运行时成功,当它第二次启动时(10 秒后),它会提示以下错误消息。

 org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={}.  If you want to run this job again, change the parameters.at org.springframework.batch.core.repository.support.SimpleJobRepository.createJobExecution(SimpleJobRepository.java:126)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 

解决办法

参考上面的错误消息"如果您想再次运行该任务,请更改参数。“公式是JobInstance = JobParameters + Job。如果您没有任何用于JobParameters的参数,只需传递一个当前时间作为参数来创建一个新的JobInstance。举个例子,

CustomJobLauncher.java

 //...@Component
public class CustomJobLauncher {@AutowiredJobLauncher jobLauncher;@AutowiredJob job;public void run() {try {JobParameters jobParameters = new JobParametersBuilder().addLong("time",System.currentTimeMillis()).toJobParameters();JobExecution execution = jobLauncher.run(job, jobParameters);System.out.println("Exit Status : " + execution.getStatus());} catch (Exception e) {e.printStackTrace();}}} 

参考

  1. Spring Batch:配置和运行作业
  2. 如何创建新的作业实例

spring batch

Spring Batch + Quartz 调度器示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-batch/spring-batch-and-quartz-scheduler-example/

在本教程中,我们将向您展示如何使用 Quartz 调度程序框架来调度每 10 秒运行一次 Spring 批处理作业。

使用的工具和库

  1. maven3
  2. Eclipse 4.2
  3. JDK 1.6
  4. 弹簧芯 3.2.2 .释放
  5. 春季批次 2.2.0 .发布
  6. 石英

这种关系如下所示:

 Spring Batch <--> Spring QuartzJobBean <--> Quartz Frameworks 

is 充当 Spring batch 和 Quartz 框架之间的桥梁。

1.项目相关性

Spring 需要spring-context-support来支持 Quartz 调度器。

pom.xml

 <project ...<properties><jdk.version>1.6</jdk.version><spring.version>3.2.2.RELEASE</spring.version><spring.batch.version>2.2.0.RELEASE</spring.batch.version><quartz.version>1.8.6</quartz.version></properties><dependencies><!-- Spring Core --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><!-- QuartzJobBean in spring-context-support.jar --><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>${spring.version}</version></dependency><!-- Quartz framework --><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>${quartz.version}</version></dependency><!-- Spring Batch dependencies --><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-core</artifactId><version>${spring.batch.version}</version></dependency><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-infrastructure</artifactId><version>${spring.batch.version}</version></dependency></dependencies>
</project> 

2.春季批处理作业

通过自定义编写器读取 csv 文件并打印内容的批处理作业。需要强调的几点:

1.配置JobRegistryBeanPostProcessor bean,它向JobRegistry注册Jobbean,这样QuartzJobBean就可以通过JobRegister (JobLocator)获得Job bean。
2。JobLauncherDetails延长QuartzJobBean,作为弹簧片和石英之间的桥梁。

job-quartz.xml

 <beans xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/batchhttp://www.springframework.org/schema/batch/spring-batch-2.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"><!-- spring batch context --><bean id="jobRepository"class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"><property name="transactionManager" ref="transactionManager" /></bean><bean id="transactionManager"class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /><bean id="jobLauncher"class="org.springframework.batch.core.launch.support.SimpleJobLauncher"><property name="jobRepository" ref="jobRepository" /></bean><beanclass="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor"><property name="jobRegistry" ref="jobRegistry" /></bean><bean id="jobRegistry"class="org.springframework.batch.core.configuration.support.MapJobRegistry" /><!-- spring batch context --><bean id="report" class="com.mkyong.model.Report" scope="prototype" /><bean id="customWriter" class="com.mkyong.writers.CustomWriter" /><batch:job id="reportJob"><batch:step id="step1"><batch:tasklet><batch:chunk reader="cvsFileItemReader" writer="customWriter"commit-interval="10"></batch:chunk></batch:tasklet></batch:step></batch:job><bean id="cvsFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader"><!-- Read a csv file --><property name="resource" value="classpath:cvs/input/report.csv" /><property name="lineMapper"><bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper"><property name="lineTokenizer"><beanclass="org.springframework.batch.item.file.transform.DelimitedLineTokenizer"><property name="names" value="id,impressions" /></bean></property><property name="fieldSetMapper"><beanclass="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper"><property name="prototypeBeanName" value="report" /></bean></property></bean></property></bean><!-- run every 10 seconds --><bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"><property name="triggers"><bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"><property name="jobDetail" ref="jobDetail" /><property name="cronExpression" value="*/10 * * * * ?" /></bean></property></bean><bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailBean"><property name="jobClass" value="com.mkyong.quartz.JobLauncherDetails" /><property name="group" value="quartz-batch" /><property name="jobDataAsMap"><map><entry key="jobName" value="reportJob" /><entry key="jobLocator" value-ref="jobRegistry" /><entry key="jobLauncher" value-ref="jobLauncher" /><entry key="param1" value="mkyong1" /><entry key="param2" value="mkyong2" /></map></property></bean></beans> 

3.QuartzJobBean 示例

这个类是从Spring batch sample Github repository复制来的,做了一点小小的改动,就是在每次作业运行时通过传递一个new Date()来运行已完成的作业。

JobLauncherDetails.java

 package com.mkyong.quartz;import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;import org.quartz.JobExecutionContext;
import org.springframework.batch.core.JobExecutionException;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.configuration.JobLocator;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.scheduling.quartz.QuartzJobBean;public class JobLauncherDetails extends QuartzJobBean {static final String JOB_NAME = "jobName";private JobLocator jobLocator;private JobLauncher jobLauncher;public void setJobLocator(JobLocator jobLocator) {this.jobLocator = jobLocator;}public void setJobLauncher(JobLauncher jobLauncher) {this.jobLauncher = jobLauncher;}@SuppressWarnings("unchecked")protected void executeInternal(JobExecutionContext context) {Map<String, Object> jobDataMap = context.getMergedJobDataMap();String jobName = (String) jobDataMap.get(JOB_NAME);JobParameters jobParameters = getJobParametersFromJobMap(jobDataMap);try {jobLauncher.run(jobLocator.getJob(jobName), jobParameters);} catch (JobExecutionException e) {e.printStackTrace();}}//get params from jobDataAsMap property, job-quartz.xmlprivate JobParameters getJobParametersFromJobMap(Map<String, Object> jobDataMap) {JobParametersBuilder builder = new JobParametersBuilder();for (Entry<String, Object> entry : jobDataMap.entrySet()) {String key = entry.getKey();Object value = entry.getValue();if (value instanceof String && !key.equals(JOB_NAME)) {builder.addString(key, (String) value);} else if (value instanceof Float || value instanceof Double) {builder.addDouble(key, ((Number) value).doubleValue());} else if (value instanceof Integer || value instanceof Long) {builder.addLong(key, ((Number) value).longValue());} else if (value instanceof Date) {builder.addDate(key, (Date) value);} else {// JobDataMap contains values which are not job parameters// (ignoring)}}//need unique job parameter to rerun the completed jobbuilder.addDate("run date", new Date());return builder.toJobParameters();}} 

4.运行它

加载 Spring 应用程序上下文,Quartz 调度程序将每 10 秒运行一次“reportJob”。

App.java

 package com.mkyong;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {String springConfig = "spring/batch/jobs/job-quartz.xml";ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);}
} 

下载源代码

Download it – SpringBatch-Quartz-Scheduler-Example.zip (20 kb)

参考

  1. Quartz–企业作业调度器
  2. Spring 3 + Quartz 1.8.6 调度器示例
  3. QuartzJobBean 示例
  4. Wiki : Cron
  5. Spring Batch+Spring task scheduler 示例

quartz scheduler spring batch

Spring 批处理示例–CSV 文件到 MySQL 数据库

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-batch/spring-batch-example-csv-file-to-database/

在本教程中,我们将向您展示如何配置 Spring 批处理作业将数据从 CSV 文件读入数据库。

使用的工具和库:

  1. maven3
  2. Eclipse 4.2
  3. JDK 1.6
  4. 弹簧芯 3.2.2 .释放
  5. 春季批次 2.2.0 .发布
  6. MySQL Java 驱动程序 5.1.25

1.Java 项目

用 Maven 创建一个 Java 项目

 $ mvn archetype:generate -DgroupId=com.mkyong -DartifactId=SpringBatchExample -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false 

转换成 Eclipse 项目,并将其导入 Eclipse IDE。

 $ cd SpringBatchExample/
$ mvn eclipse:eclipse 

2.项目相关性

pom.xml 中声明所有项目依赖关系。

pom.xml

 <project  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>SpringBatchExample</artifactId><packaging>jar</packaging><version>1.0-SNAPSHOT</version><name>SpringBatchExample</name><url>http://maven.apache.org</url><properties><jdk.version>1.6</jdk.version><spring.version>3.2.2.RELEASE</spring.version><spring.batch.version>2.2.0.RELEASE</spring.batch.version><mysql.driver.version>5.1.25</mysql.driver.version></properties><dependencies><!-- Spring Core --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><!-- Spring jdbc, for database --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><!-- Spring Batch dependencies --><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-core</artifactId><version>${spring.batch.version}</version></dependency><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-infrastructure</artifactId><version>${spring.batch.version}</version></dependency><!-- MySQL database driver --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.driver.version}</version></dependency></dependencies><build><finalName>spring-batch</finalName><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-eclipse-plugin</artifactId><version>2.9</version><configuration><downloadSources>true</downloadSources><downloadJavadocs>false</downloadJavadocs></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>${jdk.version}</source><target>${jdk.version}</target></configuration></plugin></plugins></build>
</project> 

3.项目目录结构

审查最终的项目结构。

spring-batch-csv-database-project-structure

4.CSV 文件

这是资源文件夹中的 csv 文件。

report.csv

 Date,Impressions,Clicks,Earning
6/1/13,"139,237",37,227.21
6/2/13,"149,582",55,234.71
6/3/13,"457,425",132,211.48
6/4/13,"466,870",141,298.40
6/5/13,"472,385",194,281.35
...... 

5.MySQL 数据库

为 MySQL 数据库定义一个“数据源”bean。jdbc:initialize-database用于自动创建元数据表,Spring Batch 需要它来存储作业的细节。

resources/spring/batch/config/database.xml

 <beans xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd"><!-- connect to database --><bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/test" /><property name="username" value="root" /><property name="password" value="" /></bean><bean id="transactionManager"class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /><!-- create job-meta tables automatically --><jdbc:initialize-database data-source="dataSource"><jdbc:script location="org/springframework/batch/core/schema-drop-mysql.sql" /><jdbc:script location="org/springframework/batch/core/schema-mysql.sql" /></jdbc:initialize-database></beans> 

6.弹簧批芯设置

定义jobRepositoryjobLauncher

resources/spring/batch/config/context.xml

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"><!-- stored job-metadata in database --><bean id="jobRepository"class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"><property name="dataSource" ref="dataSource" /><property name="transactionManager" ref="transactionManager" /><property name="databaseType" value="mysql" /></bean><!-- stored job-metadata in memory --><!-- <bean id="jobRepository"class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"><property name="transactionManager" ref="transactionManager" /></bean>--><bean id="jobLauncher"class="org.springframework.batch.core.launch.support.SimpleJobLauncher"><property name="jobRepository" ref="jobRepository" /></bean></beans> 

7.春季批处理作业

这是配置 Spring 批处理作业的主要 xml 文件。这个job-report.xml文件定义了一个任务来读取一个report.csv文件,将它与report plain pojo 进行匹配,并将数据写入 MySQL 数据库。

看评论,应该不言自明。顺便说一下,记得手动创建“ RAW_REPORT 表。

resources/spring/batch/jobs/job-report.xml

 <beans xmlns:batch="http://www.springframework.org/schema/batch" xmlns:task="http://www.springframework.org/schema/task"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/batchhttp://www.springframework.org/schema/batch/spring-batch-2.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"><bean id="report" class="com.mkyong.model.Report" scope="prototype" /><batch:job id="reportJob"><batch:step id="step1"><batch:tasklet><batch:chunk reader="cvsFileItemReader" writer="mysqlItemWriter"commit-interval="2"></batch:chunk></batch:tasklet></batch:step></batch:job><bean id="cvsFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader"><!-- Read a csv file --><property name="resource" value="classpath:cvs/report.csv" /><property name="lineMapper"><bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper"><!-- split it --><property name="lineTokenizer"><beanclass="org.springframework.batch.item.file.transform.DelimitedLineTokenizer"><property name="names" value="date,impressions,clicks,earning" /></bean></property><property name="fieldSetMapper">   <!-- return back to reader, rather than a mapped object. --><!--<bean class="org.springframework.batch.item.file.mapping.PassThroughFieldSetMapper" />--> <!-- map to an object --><beanclass="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper"><property name="prototypeBeanName" value="report" /></bean>			</property></bean></property></bean><bean id="mysqlItemWriter"class="org.springframework.batch.item.database.JdbcBatchItemWriter"><property name="dataSource" ref="dataSource" /><property name="sql"><value><![CDATA[        insert into RAW_REPORT(DATE,IMPRESSIONS,CLICKS,EARNING) values (:date, :impressions, :clicks, :earning)]]></value></property><!-- It will take care matching between object property and sql name parameter --><property name="itemSqlParameterSourceProvider"><beanclass="org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider" /></property></bean></beans> 

com/mkyong/model/Report.java

 package com.mkyong.model;public class Report {private String Date;private String Impressions;private String Clicks;private String Earning;//getter and setter methods} 

Note
For detail explanation, please refer to this Spring batch references.

8.运行它

加载所有内容并运行它jobLauncher。这是启动和测试它的最简单的方法,但是,在现实生活中,您可能需要使用 Spring task、Quartz 等调度程序框架或“cron”command 等系统调度程序来启动它(我将在接下来的教程中向您展示)。

com/mkyong/App.java

 package com.mkyong;import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {String[] springConfig  = {	"spring/batch/config/database.xml", "spring/batch/config/context.xml","spring/batch/jobs/job-report.xml" };ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");Job job = (Job) context.getBean("reportJob");try {JobExecution execution = jobLauncher.run(job, new JobParameters());System.out.println("Exit Status : " + execution.getStatus());} catch (Exception e) {e.printStackTrace();}System.out.println("Done");}
} 

输出。创建春季批量元数据表,report.cvs的内容被插入数据库表“ RAW_REPORT ”。

spring-batch-cvs-database-data

完成了。

下载源代码

Download it – SpringBatch-CSV-Database-Example.zip (18 kb)

参考

  1. Spring Batch–配置和运行作业
  2. Spring 批处理–元数据模式
  3. JdbcBatchItemWriter JavaDoc
  4. 用 Maven 创建一个 Java 项目

batch job csv spring batch

Spring 批处理示例——MySQL 数据库到 XML

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-batch/spring-batch-example-mysql-database-to-xml/

在本教程中,我们将向您展示如何使用JdbcCursorItemReaderJdbcPagingItemReader从 MySQL 数据库中读取数据,并将其写入 XML 文件。

使用的工具和库

  1. maven3
  2. Eclipse 4.2
  3. JDK 1.6
  4. 弹簧芯 3.2.2 .释放
  5. 春季 OXM 3.2.2 .发布
  6. 春季批次 2.2.0 .发布
  7. MySQL Java 驱动程序 5.1.25

这个例子是 MySQL JDBC(reader)-XML(writer)。

1.项目目录结构

回顾最终的项目结构,一个标准的 Maven 项目。

spring batch database to xml ## 2.数据库ˌ资料库

一个“用户”表,只包含 5 条记录,稍后用 jdbc 读取它。

users table

 id, user_login, password, age'1','mkyong','password','30'
'2','user_a','password','25'
'3','user_b','password','10'
'4','user_c','password','25'
'5','user_d','password','40' 

3.项目阅读器

创建一个行映射器,将数据库值映射到“用户”对象。

User.java

 package com.mkyong;public class User {int id;String username;String password;int age;//... getter and setter methods} 

UserRowMapper.java

 package com.mkyong;import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;public class UserRowMapper implements RowMapper<User> {@Overridepublic User mapRow(ResultSet rs, int rowNum) throws SQLException {User user = new User();user.setId(rs.getInt("id"));user.setUsername(rs.getString("user_login"));user.setPassword(rs.getString("user_pass"));user.setAge(rs.getInt("age"));return user;}} 

从数据库中读取数据的例子。

job.xml

 <bean id="itemReader"class="org.springframework.batch.item.database.JdbcCursorItemReader"scope="step"><property name="dataSource" ref="dataSource" /><property name="sql"value="select ID, USER_LOGIN, USER_PASS, AGE from USERS" /><property name="rowMapper"><bean class="com.mkyong.UserRowMapper" /></property></bean> 

大记录可以用JdbcPagingItemReader

job.xml

 <bean id="pagingItemReader"class="org.springframework.batch.item.database.JdbcPagingItemReader"scope="step"><property name="dataSource" ref="dataSource" /><property name="queryProvider"><beanclass="org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean"><property name="dataSource" ref="dataSource" /><property name="selectClause" value="select id, user_login, user_pass, age" /><property name="fromClause" value="from users" /><property name="whereClause" value="where user_login=:name" /><property name="sortKey" value="id" /></bean></property><property name="parameterValues"><map><entry key="name" value="#{jobParameters['name']}" /></map></property><property name="pageSize" value="10" /><property name="rowMapper"><bean class="com.mkyong.UserRowMapper" /></property></bean> 

4.项目作者

将数据写入 XML 文件。

job.xml

 <bean id="itemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter"><property name="resource" value="file:xml/outputs/users.xml" /><property name="marshaller" ref="userUnmarshaller" /><property name="rootTagName" value="users" /></bean><bean id="userUnmarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"><property name="aliases"><util:map id="aliases"><entry key="user" value="com.mkyong.User" /></util:map></property></bean> 

5.春季批处理作业

从 MySQL 中读取数据并将其写入 XML 文件的任务。

resources/spring/batch/jobs/job-extract-users.xml

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"><import resource="../config/context.xml" /><import resource="../config/database.xml" /><bean id="itemReader"class="org.springframework.batch.item.database.JdbcCursorItemReader"scope="step"><property name="dataSource" ref="dataSource" /><property name="sql"value="select ID, USER_LOGIN, USER_PASS, AGE from USERS where age > #{jobParameters['age']}" /><property name="rowMapper"><bean class="com.mkyong.UserRowMapper" /></property></bean><job id="testJob" ><step id="step1"><tasklet><chunk reader="pagingItemReader" writer="itemWriter"commit-interval="1" /></tasklet></step></job><bean id="itemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter"><property name="resource" value="file:xml/outputs/users.xml" /><property name="marshaller" ref="userUnmarshaller" /><property name="rootTagName" value="users" /></bean><bean id="userUnmarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"><property name="aliases"><util:map id="aliases"><entry key="user" value="com.mkyong.User" /></util:map></property></bean>	
</beans> 

resources/spring/batch/config/database.xml

 <beans xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd"><!-- connect to database --><bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/test" /><property name="username" value="root" /><property name="password" value="" /></bean><bean id="transactionManager"class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /></beans> 

6.运行它

创建一个 Java 类并运行批处理作业。

App.java

 package com.mkyong;import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {App obj = new App();obj.run();}private void run() {String[] springConfig = { "spring/batch/jobs/job-extract-users.xml" };ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");Job job = (Job) context.getBean("testJob");try {JobParameters param = new JobParametersBuilder().addString("age", "20").toJobParameters();JobExecution execution = jobLauncher.run(job, param);System.out.println("Exit Status : " + execution.getStatus());System.out.println("Exit Status : " + execution.getAllFailureExceptions());} catch (Exception e) {e.printStackTrace();}System.out.println("Done");}} 

输出。将所有“年龄大于 20 岁的用户”提取到 XML 文件中。

xml/outputs/users.xml

 <?xml version="1.0" encoding="UTF-8"?>
<users><user><id>1</id><username>mkyong</username><password>password</password><age>30</age></user><user><id>2</id><username>user_a</username><password>password</password><age>25</age></user><user><id>4</id><username>user_c</username><password>password</password><age>25</age></user><user><id>5</id><username>user_d</username><password>password</password><age>40</age></user>
</users> 

下载源代码

Download it – SpringBatch-MySQL-XML-Example.zip (22 kb)

参考

  1. 春季批次-读写器数据库
  2. staxeventitiveriter javadoc的缩写
  3. JdbcPagingItemReader JavaDoc

mysql spring batch xml

Spring 批处理示例–XML 文件到 CSV 文件

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-batch/spring-batch-example-xml-file-to-csv-file/

在本教程中,我们将向您展示如何配置一个 Spring 批处理作业来将 XML 文件(JAXB2库)读入一个csv文件,并在使用ItemProcessor写入之前过滤掉记录。

使用的工具和库

  1. maven3
  2. Eclipse 4.2
  3. JDK 1.6
  4. 弹簧芯 3.2.2 .释放
  5. 春季批次 2.2.0 .发布
  6. 春季 OXM 3.2.2 .发布

此示例–XML 文件(阅读器)–过滤(项目处理器)–CSV(编写器)。

1.简单的 Java 项目

1.用 Maven 创建一个快速启动 Java 项目,转换并导入到 Eclipse IDE 中。

 $ mvn archetype:generate -DgroupId=com.mkyong -DartifactId=SpringBatchExample3 -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false 
 $ cd SpringBatchExample3/
$ mvn eclipse:eclipse 

2.项目相关性

pom.xml中声明所有项目依赖关系

pom.xml

 <project  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>SpringBatchExample</artifactId><packaging>jar</packaging><version>1.0-SNAPSHOT</version><name>SpringBatchExample</name><url>http://maven.apache.org</url><properties><jdk.version>1.6</jdk.version><spring.version>3.2.2.RELEASE</spring.version><spring.batch.version>2.2.0.RELEASE</spring.batch.version></properties><dependencies><!-- Spring Core --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><!-- Spring XML to/back object --><dependency><groupId>org.springframework</groupId><artifactId>spring-oxm</artifactId><version>${spring.version}</version></dependency><!-- Spring Batch dependencies --><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-core</artifactId><version>${spring.batch.version}</version></dependency><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-infrastructure</artifactId><version>${spring.batch.version}</version></dependency></dependencies><build><finalName>spring-batch</finalName><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-eclipse-plugin</artifactId><version>2.9</version><configuration><downloadSources>true</downloadSources><downloadJavadocs>false</downloadJavadocs></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>${jdk.version}</source><target>${jdk.version}</target></configuration></plugin></plugins></build></project> 

3.项目目录结构

回顾最终的项目结构,了解下一步要做的事情。

spring batch xml to csv

4.XML 文件

resources/xml/report.xml

 <?xml version="1.0" encoding="UTF-8" ?>
<company><record refId="1001"><name>mkyong</name><age>31</age><dob>31/8/1982</dob><income>200,000</income></record><record refId="1002"><name>kkwong</name><age>30</age><dob>26/7/1983</dob><income>100,999</income></record><record refId="1003"><name>joel</name><age>29</age><dob>21/8/1984</dob><income>1,000,000</income></record><record refId="1004"><name>leeyy</name><age>29</age><dob>21/3/1984</dob><income>80,000.89</income></record>
</company> 

5.读取 XML 文件

在这个例子中,我们使用Jaxb2Marshaller将 XML 值和属性映射到一个对象。

resources/spring/batch/jobs/job-report.xml

 <!-- ...... --><bean id="xmlItemReader" class="org.springframework.batch.item.xml.StaxEventItemReader"><property name="fragmentRootElementName" value="record" /><property name="resource" value="classpath:xml/report.xml" /><property name="unmarshaller" ref="reportUnmarshaller" /></bean><!-- Read and map values to object, via jaxb2 --><bean id="reportUnmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"><property name="classesToBeBound"><list><value>com.mkyong.model.Report</value></list></property></bean> 

注释Report,告诉它哪个 XML 值映射到哪个字段。

Report.java

 package com.mkyong.model;import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import com.mkyong.adapter.JaxbBigDecimalAdapter;
import com.mkyong.adapter.JaxbDateAdapter;@XmlRootElement(name = "record")
public class Report {private int refId;private String name;private int age;private Date dob;private BigDecimal income;@XmlAttribute(name = "refId")public int getRefId() {return refId;}public void setRefId(int refId) {this.refId = refId;}@XmlElement(name = "age")public int getAge() {return age;}public void setAge(int age) {this.age = age;}@XmlElementpublic String getName() {return name;}public void setName(String name) {this.name = name;}@XmlJavaTypeAdapter(JaxbDateAdapter.class)@XmlElementpublic Date getDob() {return dob;}public void setDob(Date dob) {this.dob = dob;}@XmlJavaTypeAdapter(JaxbBigDecimalAdapter.class)@XmlElementpublic BigDecimal getIncome() {return income;}public void setIncome(BigDecimal income) {this.income = income;}// for csv file onlypublic String getCsvDob() {SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");return dateFormat.format(getDob());}} 

在 JAXB2 中,那些“复杂”的数据类型,如DateBigDecimal,不会自动映射到字段,即使它是带注释的。

为了让 JAXB2 支持Date转换,您需要创建一个自定义适配器来手动处理Date format,然后通过@XmlJavaTypeAdapter连接适配器。

JaxbDateAdapter.java

 package com.mkyong.adapter;import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;public class JaxbDateAdapter extends XmlAdapter<String, Date> {private SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");@Overridepublic String marshal(Date date) throws Exception {return dateFormat.format(date);}@Overridepublic Date unmarshal(String date) throws Exception {return dateFormat.parse(date);}} 

BigDecimal一样,XML 的 income 元素中的逗号“,”导致了转换问题,您也需要一个自定义适配器来处理它。

JaxbBigDecimalAdapter.java

 package com.mkyong.adapter;import java.math.BigDecimal;
import javax.xml.bind.annotation.adapters.XmlAdapter;public class JaxbBigDecimalAdapter extends XmlAdapter<String, BigDecimal> {@Overridepublic String marshal(BigDecimal obj) throws Exception {return obj.toString();}@Overridepublic BigDecimal unmarshal(String obj) throws Exception {return new BigDecimal(obj.replaceAll(",", ""));}} 

6.弹簧批芯设置

定义jobRepositoryjobLauncher

resources/spring/batch/config/context.xml

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"><!-- stored job-meta in memory --> <bean id="jobRepository"class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"><property name="transactionManager" ref="transactionManager" /></bean><bean id="transactionManager"class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /><bean id="jobLauncher"class="org.springframework.batch.core.launch.support.SimpleJobLauncher"><property name="jobRepository" ref="jobRepository" /></bean></beans> 

7.春季批处理作业

一个 Spring 批处理作业,读取report.xml文件,映射到Report对象,写入 csv 文件。看评论,应该不言自明。

resources/spring/batch/jobs/job-report.xml

 <beans xmlns:batch="http://www.springframework.org/schema/batch" xmlns:task="http://www.springframework.org/schema/task"xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/batchhttp://www.springframework.org/schema/batch/spring-batch-2.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd"><batch:job id="reportJob"><batch:step id="step1"><batch:tasklet><batch:chunk reader="xmlItemReader" writer="cvsFileItemWriter" processor="filterReportProcessor"commit-interval="1"></batch:chunk></batch:tasklet></batch:step></batch:job><!-- Filtering process --><bean id="filterReportProcessor" class="com.mkyong.processor.FilterReportProcessor" /><bean id="xmlItemReader" class="org.springframework.batch.item.xml.StaxEventItemReader"><property name="fragmentRootElementName" value="record" /><property name="resource" value="classpath:xml/report.xml" /><property name="unmarshaller" ref="reportUnmarshaller" /></bean><!-- Read and map values to object, via jaxb2 --><bean id="reportUnmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"><property name="classesToBeBound"><list><value>com.mkyong.model.Report</value></list></property></bean><bean id="cvsFileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter"><!-- write to this csv file --><property name="resource" value="file:cvs/report.csv" /><property name="shouldDeleteIfExists" value="true" /><property name="lineAggregator"><beanclass="org.springframework.batch.item.file.transform.DelimitedLineAggregator"><property name="delimiter" value="," /><property name="fieldExtractor"><beanclass="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor"><property name="names" value="refId, name, age, csvDob, income" /></bean></property></bean></property></bean></beans> 

8.春季批次–项目处理器

在 Spring batch 中,wired Processor将在写入任何资源之前被触发,因此,这是处理任何转换、过滤和业务逻辑的最佳位置。在本例中,如果其'age等于 30,则Report对象将被忽略(不写入 csv 文件)。

FilterReportProcessor.java

 package com.mkyong.processor;import org.springframework.batch.item.ItemProcessor;
import com.mkyong.model.Report;//run before writing
public class FilterReportProcessor implements ItemProcessor<Report, Report> {@Overridepublic Report process(Report item) throws Exception {//filter object which age = 30if(item.getAge()==30){return null; // null = ignore this object}return item;}} 

9.运行它

运行批处理作业的最简单方法。

App.java

 package com.mkyong;import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {String[] springConfig  = {	"spring/batch/config/context.xml","spring/batch/jobs/job-report.xml" };ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");Job job = (Job) context.getBean("reportJob");try {JobExecution execution = jobLauncher.run(job, new JobParameters());System.out.println("Exit Status : " + execution.getStatus());} catch (Exception e) {e.printStackTrace();}System.out.println("Done");}
} 

输出。XML 值被插入到 csv 文件中。

csv/report.csv

 1001,mkyong,31,31/08/1982,200000
1003,joel,29,21/08/1984,1000000
1004,leeyy,29,21/03/1984,80000.89 

output

下载源代码

Download it – SpringBatch-XML-CSV-Example.zip (81 kb)

参考

  1. Spring 批处理项目读取器和项目写入器
  2. JAXB 定制绑定–Java . util . date
  3. 如何使用 FlatFileItemWriter?
  4. flat file item writer JavaDoc

csv spring batch xml

Spring 批处理示例 MongoDB 数据库的 XML 文件

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-batch/spring-batch-example-xml-file-to-database/

在本教程中,我们将向您展示如何配置一个 Spring 批处理作业,将数据从一个 XML 文件( XStream library)读入一个 no SQL 数据库( MongoDB )。此外,创建一个单元测试用例来启动和测试批处理作业。

使用的工具和库

  1. maven3
  2. Eclipse 4.2
  3. JDK 1.6
  4. 弹簧芯 3.2.2 .释放
  5. 春季批次 2.2.0 .发布
  6. 春季批量测试 2.2.0 .发布
  7. 春季 OXM 3.2.2 .发布
  8. MongoDB Java 驱动程序 2.11.2
  9. MongoDB 2.2.3
  10. jUnit 4.11
  11. 测试 6.8.5

这个例子是 XML 文件(阅读器)MongoDB(编写器)。

1.简单的 Java 项目

1.用 Maven 创建一个快速启动 Java 项目,转换并导入到 Eclipse IDE 中。

 $ mvn archetype:generate -DgroupId=com.mkyong -DartifactId=SpringBatchExample2 -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false 
 $ cd SpringBatchExample/
$ mvn eclipse:eclipse 

2.项目相关性

pom.xml中声明所有项目依赖关系

pom.xml

 <project  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>SpringBatchExample</artifactId><packaging>jar</packaging><version>1.0-SNAPSHOT</version><name>SpringBatchExample</name><url>http://maven.apache.org</url><properties><jdk.version>1.6</jdk.version><spring.version>3.2.2.RELEASE</spring.version><spring.batch.version>2.2.0.RELEASE</spring.batch.version><spring.data.version>1.2.1.RELEASE</spring.data.version><mongodb.driver.version>2.11.2</mongodb.driver.version></properties><dependencies><!-- Spring Core --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><!-- Spring XML to/back object --><dependency><groupId>org.springframework</groupId><artifactId>spring-oxm</artifactId><version>${spring.version}</version></dependency><!-- Spring Batch dependencies --><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-core</artifactId><version>${spring.batch.version}</version></dependency><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-infrastructure</artifactId><version>${spring.batch.version}</version></dependency><!-- Spring Batch unit test --><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-test</artifactId><version>${spring.batch.version}</version></dependency><!-- MongoDB database driver --><dependency><groupId>org.mongodb</groupId><artifactId>mongo-java-driver</artifactId><version>${mongodb.driver.version}</version></dependency><!-- Spring data mongodb --><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-mongodb</artifactId><version>${spring.data.version}</version></dependency><!-- Junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><!-- Testng --><dependency><groupId>org.testng</groupId><artifactId>testng</artifactId><version>6.8.5</version><scope>test</scope></dependency></dependencies><build><finalName>spring-batch</finalName><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-eclipse-plugin</artifactId><version>2.9</version><configuration><downloadSources>true</downloadSources><downloadJavadocs>false</downloadJavadocs></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>${jdk.version}</source><target>${jdk.version}</target></configuration></plugin></plugins></build></project> 

3.项目目录结构

回顾最终的项目结构,了解下一步要做的事情。

spring batch - xml to mongodb

4.XML 文件

这是资源文件夹中的 XML 文件。

resources/xml/report.xml

 <?xml version="1.0" encoding="UTF-8" ?>
<report><record id="1"><date>6/1/2013</date><impression>139,237</impression><clicks>40</clicks><earning>220.90</earning></record><record id="2"><date>6/2/2013</date><impression>339,100</impression><clicks>60</clicks><earning>320.88</earning></record><record id="3"><date>6/3/2013</date><impression>431,436</impression><clicks>76</clicks><earning>270.80</earning></record>
</report> 

5.读取 XML 文件

在 Spring batch 中,我们可以使用StaxEventItemReader读取 XML 文件,使用XStreamMarshaller将 XML 值和属性映射到一个对象。

resources/spring/batch/jobs/job-report.xml

 <!-- ...... --><bean id="xmlItemReader" class="org.springframework.batch.item.xml.StaxEventItemReader"><property name="fragmentRootElementName" value="record" /><property name="resource" value="classpath:xml/report.xml" /><property name="unmarshaller" ref="reportUnmarshaller" /></bean><bean id="reportUnmarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"><property name="aliases"><util:map id="aliases"><entry key="record" value="com.mkyong.model.Report" /></util:map></property><property name="converters"><array><ref bean="reportConverter" /></array></property></bean><bean id="reportConverter" class="com.mkyong.converter.ReportConverter" /> 

Report.java

 package com.mkyong.model;import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;public class Report {private int id;private Date date;private long impression;private int clicks;private BigDecimal earning;//getter and setter methods} 

要将 XML 值映射到像DateBigDecimal这样的“复杂”数据类型,您需要附加一个自定义的converter来手动转换和映射值。

ReportConverter.java

 package com.mkyong.converter;import java.math.BigDecimal;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;import com.mkyong.model.Report;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;public class ReportConverter implements Converter {@Overridepublic boolean canConvert(Class type) {//we only need "Report" objectreturn type.equals(Report.class);}@Overridepublic void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {//do nothing}@Overridepublic Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {Report obj = new Report();//get attributeobj.setId(Integer.valueOf(reader.getAttribute("id")));reader.moveDown(); //get dateDate date = null;try {date = new SimpleDateFormat("M/d/yyyy").parse(reader.getValue());} catch (ParseException e) {e.printStackTrace();}obj.setDate(date);reader.moveUp();reader.moveDown(); //get impressionString impression = reader.getValue();NumberFormat format = NumberFormat.getInstance(Locale.US);Number number = 0;try {number = format.parse(impression);} catch (ParseException e) {e.printStackTrace();}obj.setImpression(number.longValue());reader.moveUp();reader.moveDown(); //get clickobj.setClicks(Integer.valueOf(reader.getValue()));reader.moveUp();reader.moveDown(); //get earningobj.setEarning(new BigDecimal(reader.getValue()));reader.moveUp();return obj;}
} 

6.MongoDB 数据库

定义一个 mongodb 实例和一个mongoTemplate

resources/spring/batch/config/database.xml

 <beans xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/data/mongohttp://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd"><!-- connect to mongodb --><mongo:mongo host="127.0.0.1" port="27017" /><mongo:db-factory dbname="yourdb" /><bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"><constructor-arg name="mongoDbFactory" ref="mongoDbFactory" /></bean></beans> 

7.弹簧批芯设置

定义jobRepositoryjobLauncher

resources/spring/batch/config/context.xml

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"><!-- stored job-meta in memory --> <bean id="jobRepository"class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"><property name="transactionManager" ref="transactionManager" /></bean><bean id="transactionManager"class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /><bean id="jobLauncher"class="org.springframework.batch.core.launch.support.SimpleJobLauncher"><property name="jobRepository" ref="jobRepository" /></bean></beans> 

8.春季批处理作业

一个 Spring 批处理作业,读取report.xml文件,映射到一个Report对象,并将其写入MongoDB。看评论,应该不言自明。

resources/spring/batch/jobs/job-report.xml

 <beans xmlns:batch="http://www.springframework.org/schema/batch" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/batchhttp://www.springframework.org/schema/batch/spring-batch-2.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd"><batch:job id="reportJob"><batch:step id="step1"><batch:tasklet><batch:chunk reader="xmlItemReader" writer="mongodbItemWriter"commit-interval="1"></batch:chunk></batch:tasklet></batch:step></batch:job><!-- Read XML file --><bean id="xmlItemReader" class="org.springframework.batch.item.xml.StaxEventItemReader"><property name="fragmentRootElementName" value="record" /><property name="resource" value="classpath:xml/report.xml" /><property name="unmarshaller" ref="reportUnmarshaller" /></bean><!-- Maps XML values to Object --><bean id="reportUnmarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"><property name="aliases"><util:map id="aliases"><entry key="record" value="com.mkyong.model.Report" /></util:map></property><!-- attach a custom converter --><property name="converters"><array><ref bean="reportConverter" /></array></property></bean><bean id="reportConverter" class="com.mkyong.converter.ReportConverter" />//write it to MongoDB, 'report' collection (table)<bean id="mongodbItemWriter" class="org.springframework.batch.item.data.MongoItemWriter"><property name="template" ref="mongoTemplate" /><property name="collection" value="report" /></bean></beans> 

9.单元测试

用 jUnit 或 TestNG 框架对其进行单元测试。首先,您必须手动声明JobLauncherTestUtils

test/resources/spring/batch/config/test-context.xml

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"><!-- this bean should auto load --><bean class="org.springframework.batch.test.JobLauncherTestUtils"/></beans> 

jUnit 示例

AppTest.java

 package com.mkyong;import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring/batch/jobs/job-report.xml","classpath:spring/batch/config/context.xml","classpath:spring/batch/config/database.xml","classpath:spring/batch/config/test-context.xml"})
public class AppTest {@Autowiredprivate JobLauncherTestUtils jobLauncherTestUtils;@Testpublic void launchJob() throws Exception {//JobExecution jobExecution = jobLauncherTestUtils.launchJob();JobExecution jobExecution = jobLauncherTestUtils.launchStep("step1");assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());}
} 

测试示例

AppTest2.java

 package com.mkyong;import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.Test;@ContextConfiguration(locations = {"classpath:spring/batch/jobs/job-report.xml","classpath:spring/batch/config/context.xml","classpath:spring/batch/config/database.xml","classpath:spring/batch/config/test-context.xml"})
public class AppTest2 extends AbstractTestNGSpringContextTests {@Autowiredprivate JobLauncherTestUtils jobLauncherTestUtils;@Testpublic void launchJob() throws Exception {JobExecution jobExecution = jobLauncherTestUtils.launchJob();Assert.assertEquals(jobExecution.getStatus(), BatchStatus.COMPLETED);}
} 

输出。XML 值被插入 MongoDB。

 mongo
MongoDB shell version: 2.2.3
connecting to: test> use yourdb
switched to db yourdb
> show collections
report
system.indexes> db.report.find()
{ "_id" : 1, "_class" : "com.mkyong.model.Report", 
"date" : ISODate("2013-05-31T16:00:00Z"), "impression" : NumberLong(139237), 
"clicks" : 40, "earning" : "220.90" }{ "_id" : 2, "_class" : "com.mkyong.model.Report", 
"date" : ISODate("2013-06-01T16:00:00Z"), "impression" : NumberLong(339100), 
"clicks" : 60, "earning" : "320.88" }{ "_id" : 3, "_class" : "com.mkyong.model.Report", 
"date" : ISODate("2013-06-02T16:00:00Z"), "impression" : NumberLong(431436), 
"clicks" : 76, "earning" : "270.80" }
> 

10.作业元数据怎么样?

对不起,我还没有解决这个问题的方法。据我所知,作业元数据需要关系数据库,以确保作业的可重启性和回滚。按照设计,MongoDB 没有“可靠的”事务管理。

解决方案 1:创建另一个关系数据库来存储作业元数据,嗯……这听起来很愚蠢,但很有效。你有更好的主意吗?

解决方案 2:等待 Spring 的团队对此提出解决方案。

下载源代码

Download it – SpringBatch-XML-MongoDB-Example.zip (81 kb)

参考

  1. XStream 转换器教程
  2. 对非 RDBMS 的 Spring 批量支持
  3. Spring 批处理 XML 项读取器和写入器
  4. Spring Batch–配置和运行作业
  5. 用 Maven 创建一个 Java 项目

mongodb spring batch xml

春季批次 Hello World 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-batch/spring-batch-hello-world-example/

Spring Batch 是一个批处理框架——执行一系列作业。在 Spring Batch 中,一个作业由许多步骤组成,每个步骤由一个READ-PROCESS-WRITE任务或single operation 任务(小任务)组成。

  1. 对于“读取-处理-写入”过程,它意味着从资源(csv、xml 或数据库)中“读取”数据,“处理”它并将它“写入”到其他资源(csv、xml 和数据库)。例如,一个步骤可以从 CSV 文件中读取数据,对其进行处理并将其写入数据库。Spring Batch 提供了许多用来读/写 CSV、XML 和数据库的类。
  2. 对于“单个”操作任务(tasklet),它意味着只执行单个任务,比如在一个步骤开始或完成之前或之后清理资源。
  3. 并且这些步骤可以链接在一起作为一个作业运行。
 1 Job = Many Steps.
1 Step = 1 READ-PROCESS-WRITE or 1 Tasklet.
Job = {Step 1 -> Step 2 -> Step 3} (Chained together) 

春季批次示例

考虑以下批处理作业:

  1. 步骤 1–从文件夹 A 读取 CSV 文件,处理,将其写入文件夹 b。“读取-处理-写入”
  2. 步骤 2-从文件夹 B 中读取 CSV 文件,处理,将其写入数据库。"读取-处理-写入"
  3. 步骤 3–从文件夹 b“Tasklet”中删除 CSB 文件
  4. 步骤 4-从数据库中读取数据,处理并生成 XML 格式的统计报告,将其写入文件夹 c。“读取-处理-写入”
  5. 第 5 步-阅读报告并将其发送至经理邮箱。“小任务”

在 Spring 批处理中,我们可以声明如下:

 <job id="abcJob" ><step id="step1" next="step2"><tasklet><chunk reader="cvsItemReader" writer="cvsItemWriter"  processor="itemProcesser" commit-interval="1" /></tasklet></step><step id="step2" next="step3"><tasklet><chunk reader="cvsItemReader" writer="databaseItemWriter"  processor="itemProcesser" commit-interval="1" /></tasklet></step><step id="step3" next="step4"><tasklet ref="fileDeletingTasklet" /></step><step id="step4" next="step5"><tasklet><chunk reader="databaseItemReader" writer="xmlItemWriter"  processor="itemProcesser" commit-interval="1" /></tasklet></step><step id="step5"><tasklet ref="sendingEmailTasklet" /></step></job> 

整个作业和步骤的执行都存储在数据库中,这使得失败的步骤能够从失败的地方重新开始,而不需要重新开始整个作业。

1.辅导的

在这个 Spring 批处理教程中,我们将向您展示如何创建作业、读取 CSV 文件、处理它、将输出写入 XML 文件。

使用的工具和库

  1. maven3
  2. Eclipse 4.2
  3. JDK 1.6
  4. 弹簧芯 3.2.2 .释放
  5. 春季 OXM 3.2.2 .发布
  6. 春季 JDBC 3.2.2 .发布
  7. 春季批次 2.2.0 .发布

2.项目目录

查看最终项目目录,这是一个标准的 Maven 项目。

spring-batch-hello-world-directory

3.项目相关性

他们必须依赖的只是 Spring Core、Spring Batch 和 JDK 1.5。阅读注释,了解更多信息。

pom.xml

 <project  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>SpringBatchExample</artifactId><packaging>jar</packaging><version>1.0-SNAPSHOT</version><name>SpringBatchExample</name><url>http://maven.apache.org</url><properties><jdk.version>1.6</jdk.version><spring.version>3.2.2.RELEASE</spring.version><spring.batch.version>2.2.0.RELEASE</spring.batch.version><mysql.driver.version>5.1.25</mysql.driver.version><junit.version>4.11</junit.version></properties><dependencies><!-- Spring Core --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><!-- Spring jdbc, for database --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><!-- Spring XML to/back object --><dependency><groupId>org.springframework</groupId><artifactId>spring-oxm</artifactId><version>${spring.version}</version></dependency><!-- MySQL database driver --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.driver.version}</version></dependency><!-- Spring Batch dependencies --><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-core</artifactId><version>${spring.batch.version}</version></dependency><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-infrastructure</artifactId><version>${spring.batch.version}</version></dependency><!-- Spring Batch unit test --><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-test</artifactId><version>${spring.batch.version}</version></dependency><!-- Junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version><scope>test</scope></dependency></dependencies><build><finalName>spring-batch</finalName><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-eclipse-plugin</artifactId><version>2.9</version><configuration><downloadSources>true</downloadSources><downloadJavadocs>false</downloadJavadocs></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>${jdk.version}</source><target>${jdk.version}</target></configuration></plugin></plugins></build>
</project> 

4.春季批处理作业

CSV 文件。

report.csv

 1001,"213,100",980,"mkyong", 29/7/2013
1002,"320,200",1080,"staff 1", 30/7/2013
1003,"342,197",1200,"staff 2", 31/7/2013 

一个 Spring 批处理作业,用FlatFileItemReader读取上述 csv 文件,用itemProcessor处理数据,用StaxEventItemWriter将数据写入 XML 文件

job-hello-world.xml

 <beans xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/batchhttp://www.springframework.org/schema/batch/spring-batch-2.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"><import resource="../config/context.xml" /><import resource="../config/database.xml" /><bean id="report" class="com.mkyong.model.Report" scope="prototype" /><bean id="itemProcessor" class="com.mkyong.CustomItemProcessor" /><batch:job id="helloWorldJob"><batch:step id="step1"><batch:tasklet><batch:chunk reader="cvsFileItemReader" writer="xmlItemWriter" processor="itemProcessor" commit-interval="10"></batch:chunk></batch:tasklet></batch:step></batch:job><bean id="cvsFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader"><property name="resource" value="classpath:cvs/input/report.csv" /><property name="lineMapper"><bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper"><property name="lineTokenizer"><beanclass="org.springframework.batch.item.file.transform.DelimitedLineTokenizer"><property name="names" value="id,sales,qty,staffName,date" /></bean></property><property name="fieldSetMapper"><bean class="com.mkyong.ReportFieldSetMapper" /><!-- if no data type conversion, use BeanWrapperFieldSetMapper to map by name<beanclass="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper"><property name="prototypeBeanName" value="report" /></bean>--></property></bean></property></bean><bean id="xmlItemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter"><property name="resource" value="file:xml/outputs/report.xml" /><property name="marshaller" ref="reportMarshaller" /><property name="rootTagName" value="report" /></bean><bean id="reportMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"><property name="classesToBeBound"><list><value>com.mkyong.model.Report</value></list></property></bean></beans> 

将 CSV 值映射到Report对象,并将其写入 XML 文件(通过 jaxb 注释)。

Report.java

 package com.mkyong.model;import java.math.BigDecimal;
import java.util.Date;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;@XmlRootElement(name = "record")
public class Report {private int id;private BigDecimal sales;private int qty;private String staffName;private Date date;@XmlAttribute(name = "id")public int getId() {return id;}public void setId(int id) {this.id = id;}@XmlElement(name = "sales")public BigDecimal getSales() {return sales;}public void setSales(BigDecimal sales) {this.sales = sales;}@XmlElement(name = "qty")public int getQty() {return qty;}public void setQty(int qty) {this.qty = qty;}@XmlElement(name = "staffName")public String getStaffName() {return staffName;}public void setStaffName(String staffName) {this.staffName = staffName;}public Date getDate() {return date;}public void setDate(Date date) {this.date = date;}@Overridepublic String toString() {return "Report [id=" + id + ", sales=" + sales + ", qty=" + qty + ", staffName=" + staffName + "]";}} 

要转换一个Date,需要一个自定义的FieldSetMapper。如果没有数据类型转换,只需使用BeanWrapperFieldSetMapper自动按名称映射值。

ReportFieldSetMapper.java

 package com.mkyong;import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;import com.mkyong.model.Report;public class ReportFieldSetMapper implements FieldSetMapper<Report> {private SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");@Overridepublic Report mapFieldSet(FieldSet fieldSet) throws BindException {Report report = new Report();report.setId(fieldSet.readInt(0));report.setSales(fieldSet.readBigDecimal(1));report.setQty(fieldSet.readInt(2));report.setStaffName(fieldSet.readString(3));//default format yyyy-MM-dd//fieldSet.readDate(4);String date = fieldSet.readString(4);try {report.setDate(dateFormat.parse(date));} catch (ParseException e) {e.printStackTrace();}return report;}} 

itemProcessor 将在 itemWriter 之前被激发。

CustomItemProcessor.java

 package com.mkyong;import org.springframework.batch.item.ItemProcessor;
import com.mkyong.model.Report;public class CustomItemProcessor implements ItemProcessor<Report, Report> {@Overridepublic Report process(Report item) throws Exception {System.out.println("Processing..." + item);return item;}} 

Spring 上下文和数据库配置。

context.xml

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"><!-- stored job-meta in memory --><!--  <bean id="jobRepository"class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"><property name="transactionManager" ref="transactionManager" /></bean>--><!-- stored job-meta in database --><bean id="jobRepository"class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"><property name="dataSource" ref="dataSource" /><property name="transactionManager" ref="transactionManager" /><property name="databaseType" value="mysql" /></bean><bean id="transactionManager"class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /><bean id="jobLauncher"class="org.springframework.batch.core.launch.support.SimpleJobLauncher"><property name="jobRepository" ref="jobRepository" /></bean></beans> 

database.xml

 <beans xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd"><!-- connect to MySQL database --><bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/test" /><property name="username" value="root" /><property name="password" value="" /></bean><bean id="transactionManager"class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /><!-- create job-meta tables automatically --><jdbc:initialize-database data-source="dataSource"><jdbc:script location="org/springframework/batch/core/schema-drop-mysql.sql" /><jdbc:script location="org/springframework/batch/core/schema-mysql.sql" /></jdbc:initialize-database></beans> 

5.运行它

运行批处理作业的最简单方法。

 package com.mkyong;import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {String[] springConfig  = {	"spring/batch/jobs/job-hello-world.xml" };ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");Job job = (Job) context.getBean("helloWorldJob");try {JobExecution execution = jobLauncher.run(job, new JobParameters());System.out.println("Exit Status : " + execution.getStatus());} catch (Exception e) {e.printStackTrace();}System.out.println("Done");}
} 

输出

report.xml

 <?xml version="1.0" encoding="UTF-8"?>
<report><record id="1001"><date>2013-07-29T00:00:00+08:00</date><qty>980</qty><sales>213100</sales><staffName>mkyong</staffName></record><record id="1002"><date>2013-07-30T00:00:00+08:00</date><qty>1080</qty><sales>320200</sales><staffName>staff 1</staffName></record><record id="1003"><date>2013-07-31T00:00:00+08:00</date><qty>1200</qty><sales>342197</sales><staffName>staff 2</staffName></record>
</report> 

在控制台中

 Jul 30, 2013 11:52:00 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=helloWorldJob]] launched with the following parameters: [{}]
Jul 30, 2013 11:52:00 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [step1]
Processing...Report [id=1001, sales=213100, qty=980, staffName=mkyong]
Processing...Report [id=1002, sales=320200, qty=1080, staffName=staff 1]
Processing...Report [id=1003, sales=342197, qty=1200, staffName=staff 2]
Jul 30, 2013 11:52:00 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=helloWorldJob]] completed with the following parameters: [{}] and the following status: [COMPLETED]
Exit Status : COMPLETED
Done 

下载源代码

Download it – SpringBatch-Hello-World-Example.zip (27 kb)

参考

  1. 什么是批处理
  2. 春季批量框架
  3. 春季批次–参考文件

hello world spring batch

Spring 批处理侦听器示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-batch/spring-batch-listeners-example/

spring-batch-listeners

在 Spring batch 中,有六个“监听器”来拦截步骤执行,我相信类名应该是不言自明的。

  1. StepExecutionListener
  2. itemreadlsitener
  3. ItemProcessListener
  4. ItemWriteListener
  5. ChunkListener
  6. SkipListener

1.监听器示例

三个监听器示例,什么也不做,只是打印出一条消息。

CustomStepListener.java

 package com.mkyong.listeners;import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;public class CustomStepListener implements StepExecutionListener {@Overridepublic void beforeStep(StepExecution stepExecution) {System.out.println("StepExecutionListener - beforeStep");}@Overridepublic ExitStatus afterStep(StepExecution stepExecution) {System.out.println("StepExecutionListener - afterStep");return null;}} 

CustomItemReaderListener.java

 package com.mkyong.listeners;import org.springframework.batch.core.ItemReadListener;
import com.mkyong.Domain;public class CustomItemReaderListener implements ItemReadListener<Domain> {@Overridepublic void beforeRead() {System.out.println("ItemReadListener - beforeRead");}@Overridepublic void afterRead(Domain item) {System.out.println("ItemReadListener - afterRead");}@Overridepublic void onReadError(Exception ex) {System.out.println("ItemReadListener - onReadError");}} 

CustomItemWriterListener.java

 package com.mkyong.listeners;import java.util.List;
import org.springframework.batch.core.ItemWriteListener;
import com.mkyong.Domain;public class CustomItemWriterListener implements ItemWriteListener<Domain> {@Overridepublic void beforeWrite(List<? extends Domain> items) {System.out.println("ItemWriteListener - beforeWrite");}@Overridepublic void afterWrite(List<? extends Domain> items) {System.out.println("ItemWriteListener - afterWrite");}@Overridepublic void onWriteError(Exception exception, List<? extends Domain> items) {System.out.println("ItemWriteListener - onWriteError");}} 

2.批处理作业

一个批处理作业,附加在三个侦听器上。

spring-batch-job.xml

 <bean id="customStepListener" class="com.mkyong.listeners.CustomStepListener" /><bean id="customItemReaderListener" class="com.mkyong.listeners.CustomItemReaderListener" /><bean id="customItemWriterListener" class="com.mkyong.listeners.CustomItemWriterListener" /><job id="readFileJob" ><step id="step1"><tasklet><chunk reader="multiResourceReader" writer="flatFileItemWriter"commit-interval="1" /><listeners><listener ref="customStepListener" /><listener ref="customItemReaderListener" /><listener ref="customItemWriterListener" /></listeners></tasklet></step></job> 

假设加载了 csv 文件中的 3 条记录,并将其写入某个地方,控制台输出如下:

 StepExecutionListener - beforeStepItemReadListener - beforeRead
ItemReadListener - afterRead
ItemWriteListener - beforeWrite
ItemWriteListener - afterWriteItemReadListener - beforeRead
ItemReadListener - afterRead
ItemWriteListener - beforeWrite
ItemWriteListener - afterWriteItemReadListener - beforeRead
ItemReadListener - afterRead
ItemWriteListener - beforeWrite
ItemWriteListener - afterWriteStepExecutionListener - afterStep 

下载源代码

Download it – SpringBatch-Listener-Example.zip (14 KB)

参考

  1. 截取步骤执行
  2. StepExecutionListener JavaDoc
  3. ItemReadListener JavaDoc
  4. ItemProcessListener JavaDoc
  5. ItemWriteListener JavaDoc
  6. 分块侦听器 JavaDoc
  7. SkipListener JavaDoc

listener spring batch

Spring 批量元数据表不是自动创建的?

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-batch/spring-batch-metadata-tables-are-not-created-automatically/

如果使用MapJobRepositoryFactoryBean(内存中的元数据)创建了jobRepository,则 Spring 批处理作业正在成功运行。

spring-config.xml

 <bean id="jobRepository"class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"><property name="transactionManager" ref="transactionManager" /></bean> 

问题

更改jobRepository将元数据存储到数据库后:

spring-config.xml

 <bean id="jobRepository"class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"><property name="dataSource" ref="dataSource" /><property name="transactionManager" ref="transactionManager" /><property name="databaseType" value="mysql" /></bean><bean id="jobLauncher"class="org.springframework.batch.core.launch.support.SimpleJobLauncher"><property name="jobRepository" ref="jobRepository" /></bean><bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/test" /><property name="username" value="root" /><property name="password" value="" /></bean> 

它提示batch_job_instance表不存在?为什么 Spring 没有自动创建那些元表?

 Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table db.batch_job_instance' doesn't existat sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)at java.lang.reflect.Constructor.newInstance(Constructor.java:513)at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) 

解决办法

元表的脚本存储在spring-batch.jar中,您需要手动创建它。

spring-batch-meta-data-tables

通常,您可以通过 Spring XML 配置文件自动创建表脚本。举个例子,

spring-config.xml

 <beans xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd"><!-- connect to database --><bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/test" /><property name="username" value="root" /><property name="password" value="" /></bean><!-- create job-meta tables automatically --><jdbc:initialize-database data-source="dataSource"><jdbc:script location="org/springframework/batch/core/schema-drop-mysql.sql" /><jdbc:script location="org/springframework/batch/core/schema-mysql.sql" /></jdbc:initialize-database></beans> 

再次运行 Spring 批处理作业,这些元表将被自动创建。

参考

  1. Spring 批处理–元数据模式

spring batch

spring Batch multi source item reader 示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-batch/spring-batch-multiresourceitemreader-example/

在本教程中,我们将向您展示如何从多个资源(多个 csv 文件)读取项目,并将项目写入单个 csv 文件。

使用的工具和库

  1. maven3
  2. Eclipse 4.2
  3. JDK 1.6
  4. 弹簧芯 3.2.2 .释放
  5. 春季批次 2.2.0 .发布

本例–3 个 CSV 文件(阅读器)–合并成一个 CSV 文件(写入器)。

1.项目目录结构

回顾最终的项目结构,一个标准的 Maven 项目。

spring-batch-MultiResourceItemReader-example ## 2.多个 CSV 文件

有 3 个 csv 文件,稍后我们将使用MultiResourceItemReader来逐个读取。

csv/inputs/domain-1-3-2013.csv

 1,facebook.com
2,yahoo.com
3,google.com 

csv/inputs/domain-2-3-2013.csv

 200,mkyong.com
300,stackoverflow.com
400,oracle.com 

csv/inputs/domain-3-3-2013.csv

 999,eclipse.org
888,baidu.com 

3.春季批处理作业

读取与这个模式csv/inputs/domain-*.csv匹配的资源,并将其写入单个 cvs 文件domain.all.csv的任务。

resources/spring/batch/jobs/job-read-files.xml

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"><import resource="../config/context.xml" /><bean id="domain" class="com.mkyong.Domain" /><job id="readMultiFileJob" ><step id="step1"><tasklet><chunk reader="multiResourceReader" writer="flatFileItemWriter"commit-interval="1" /></tasklet></step></job><bean id="multiResourceReader"class=" org.springframework.batch.item.file.MultiResourceItemReader"><property name="resources" value="file:csv/inputs/domain-*.csv" /><property name="delegate" ref="flatFileItemReader" /></bean><bean id="flatFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader"><property name="lineMapper"><bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper"><property name="lineTokenizer"><bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer"><property name="names" value="id, domain" /></bean></property><property name="fieldSetMapper"><beanclass="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper"><property name="prototypeBeanName" value="domain" /></bean></property></bean></property></bean><bean id="flatFileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter"><property name="resource" value="file:csv/outputs/domain.all.csv" /><property name="appendAllowed" value="true" /><property name="lineAggregator"><beanclass="org.springframework.batch.item.file.transform.DelimitedLineAggregator"><property name="delimiter" value="," /><property name="fieldExtractor"><bean	class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor"><property name="names" value="id, domain" /></bean></property></bean></property></bean></beans> 

resources/spring/batch/config/context.xml

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"><!-- stored job-meta in memory --> <bean id="jobRepository"class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"><property name="transactionManager" ref="transactionManager" /></bean><bean id="transactionManager"class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /><bean id="jobLauncher"class="org.springframework.batch.core.launch.support.SimpleJobLauncher"><property name="jobRepository" ref="jobRepository" /></bean></beans> 

4.运行它

创建一个 Java 类并运行批处理作业。

App.java

 package com.mkyong;import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {App obj = new App();obj.run();}private void run() {String[] springConfig = { "spring/batch/jobs/job-read-files.xml" };ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");Job job = (Job) context.getBean("readMultiFileJob");try {JobExecution execution = jobLauncher.run(job, new JobParameters());System.out.println("Exit Status : " + execution.getStatus());} catch (Exception e) {e.printStackTrace();}System.out.println("Done");}} 

输出。三个 csv 文件内容被读取并组合成一个 csv 文件。

csv/outputs/domain.all.csv

 1,facebook.com
2,yahoo.com
3,google.coms
200,mkyong.com
300,stackoverflow.com
400,oracle.com
999,eclipse.org
888,baidu.com 

下载源代码

Download it – SpringBatch-MultiResourceItemReader-Example.zip (12 kb)

参考

  1. MultiResourceItemReader JavaDoc
  2. flat file item writer JavaDoc
  3. 春季批量单据-多档案输入

spring batch

Spring 批量分区示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-batch/spring-batch-partitioning-example/

spring batch partitioning

图片来源:春天来源

在 Spring Batch 中,“分区”是“多个线程各自处理一系列数据”。例如,假设您在一个表中有 100 条记录,该表的“主 id”从 1 到 100,您希望处理全部 100 条记录。

通常,该过程从 1 到 100 开始,例如单线程。该过程估计需要 10 分钟才能完成。

 Single Thread - Process from 1 to 100 

在“分区”中,我们可以启动 10 个线程,每个线程处理 10 条记录(基于“id”的范围)。现在,这个过程可能只需要 1 分钟就能完成。

 Thread 1 - Process from 1 to 10
Thread 2 - Process from 11 to 20
Thread 3 - Process from 21 to 30
......
Thread 9 - Process from 81 to 90
Thread 10 - Process from 91 to 100 

要实现“分区”技术,您必须理解要处理的输入数据的结构,以便您可以正确地规划“数据范围”。

1.辅导的

在本教程中,我们将向您展示如何创建一个“分区程序”作业,该作业有 10 个线程,每个线程将根据提供的“id”范围从数据库中读取记录。

使用的工具和库

  1. maven3
  2. Eclipse 4.2
  3. JDK 1.6
  4. 弹簧芯 3.2.2 .释放
  5. 春季批次 2.2.0 .发布
  6. MySQL Java 驱动程序 5.1.25

假设“用户”表有 100 条记录。

users table structure

 id, user_login, user_passs, age1,user_1,pass_1,20
2,user_2,pass_2,40
3,user_3,pass_3,70
4,user_4,pass_4,5
5,user_5,pass_5,52
......
99,user_99,pass_99,89
100,user_100,pass_100,76 

2.项目目录结构

回顾最终的项目结构,一个标准的 Maven 项目。

spring-batch-partitioner-before

3.瓜分者ˌ分割者

首先,创建一个Partitioner实现,将分区范围放入ExecutionContext中。稍后,您将在批处理作业 XML 文件中声明相同的fromIdtied

在这种情况下,分区范围如下所示:

 Thread 1 = 1 - 10
Thread 2 = 11 - 20
Thread 3 = 21 - 30
......
Thread 10 = 91 - 100 

RangePartitioner.java

 package com.mkyong.partition;import java.util.HashMap;
import java.util.Map;import org.springframework.batch.core.partition.support.Partitioner;
import org.springframework.batch.item.ExecutionContext;public class RangePartitioner implements Partitioner {@Overridepublic Map<String, ExecutionContext> partition(int gridSize) {Map<String, ExecutionContext> result = new HashMap<String, ExecutionContext>();int range = 10;int fromId = 1;int toId = range;for (int i = 1; i <= gridSize; i++) {ExecutionContext value = new ExecutionContext();System.out.println("\nStarting : Thread" + i);System.out.println("fromId : " + fromId);System.out.println("toId : " + toId);value.putInt("fromId", fromId);value.putInt("toId", toId);// give each thread a name, thread 1,2,3value.putString("name", "Thread" + i);result.put("partition" + i, value);fromId = toId + 1;toId += range;}return result;}} 

4.批处理作业

查看批处理作业 XML 文件,它应该是不言自明的。需要强调的几点:

  1. 对于分区器, grid-size =线程数量
  2. 对于 pagingItemReader bean,一个 jdbc 阅读器示例,#{stepExecutionContext[fromId, toId]}值将由 rangePartitioner 中的ExecutionContext注入。
  3. 对于 itemProcessor bean,#{stepExecutionContext[name]}值将由 rangePartitioner 中的ExecutionContext注入。
  4. 对于编写器,每个线程将输出不同 csv 文件中的记录,文件名格式- users.processed[fromId]}-[toId].csv

job-partitioner.xml

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:batch="http://www.springframework.org/schema/batch"xmlns:util="http://www.springframework.org/schema/util"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd"><!-- spring batch core settings --><import resource="../config/context.xml" /><!-- database settings --><import resource="../config/database.xml" /><!-- partitioner job --><job id="partitionJob" ><!-- master step, 10 threads (grid-size)  --><step id="masterStep"><partition step="slave" partitioner="rangePartitioner"><handler grid-size="10" task-executor="taskExecutor" /></partition></step></job><!-- each thread will run this job, with different stepExecutionContext values. --><step id="slave" ><tasklet><chunk reader="pagingItemReader" writer="flatFileItemWriter"processor="itemProcessor" commit-interval="1" /></tasklet></step><bean id="rangePartitioner" class="com.mkyong.partition.RangePartitioner" /><bean id="taskExecutor" class="org.springframework.core.task.SimpleAsyncTaskExecutor" /><!-- inject stepExecutionContext --><bean id="itemProcessor" class="com.mkyong.processor.UserProcessor" scope="step"><property name="threadName" value="#{stepExecutionContext[name]}" /></bean><bean id="pagingItemReader"class="org.springframework.batch.item.database.JdbcPagingItemReader"scope="step"><property name="dataSource" ref="dataSource" /><property name="queryProvider"><beanclass="org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean"><property name="dataSource" ref="dataSource" /><property name="selectClause" value="select id, user_login, user_pass, age" /><property name="fromClause" value="from users" /><property name="whereClause" value="where id >= :fromId and id <= :toId" /><property name="sortKey" value="id" /></bean></property><!-- Inject via the ExecutionContext in rangePartitioner --><property name="parameterValues"><map><entry key="fromId" value="#{stepExecutionContext[fromId]}" /><entry key="toId" value="#{stepExecutionContext[toId]}" /></map></property><property name="pageSize" value="10" /><property name="rowMapper"><bean class="com.mkyong.UserRowMapper" /></property></bean><!-- csv file writer --><bean id="flatFileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter"scope="step" ><property name="resource"value="file:csv/outputs/users.processed#{stepExecutionContext[fromId]}-#{stepExecutionContext[toId]}.csv" /><property name="appendAllowed" value="false" /><property name="lineAggregator"><beanclass="org.springframework.batch.item.file.transform.DelimitedLineAggregator"><property name="delimiter" value="," /><property name="fieldExtractor"><beanclass="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor"><property name="names" value="id, username, password, age" /></bean></property></bean></property></bean></beans> 

项目处理器类仅用于打印出正在处理的项目和当前运行的“线程名”。

UserProcessor.java - item processor

 package com.mkyong.processor;import org.springframework.batch.item.ItemProcessor;
import com.mkyong.User;public class UserProcessor implements ItemProcessor<User, User> {private String threadName;@Overridepublic User process(User item) throws Exception {System.out.println(threadName + " processing : " + item.getId() + " : " + item.getUsername());return item;}public String getThreadName() {return threadName;}public void setThreadName(String threadName) {this.threadName = threadName;}} 

5.运行它

加载所有内容并运行它...将启动 10 个线程来处理所提供的数据范围。

 package com.mkyong;import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class PartitionApp {public static void main(String[] args) {PartitionApp obj = new PartitionApp ();obj.runTest();}private void runTest() {String[] springConfig = { "spring/batch/jobs/job-partitioner.xml" };ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");Job job = (Job) context.getBean("partitionJob");try {JobExecution execution = jobLauncher.run(job, new JobParameters());System.out.println("Exit Status : " + execution.getStatus());System.out.println("Exit Status : " + execution.getAllFailureExceptions());} catch (Exception e) {e.printStackTrace();}System.out.println("Done");}
} 

控制台输出

 Starting : Thread1
fromId : 1
toId : 10Starting : Thread2
fromId : 11
toId : 20Starting : Thread3
fromId : 21
toId : 30Starting : Thread4
fromId : 31
toId : 40Starting : Thread5
fromId : 41
toId : 50Starting : Thread6
fromId : 51
toId : 60Starting : Thread7
fromId : 61
toId : 70Starting : Thread8
fromId : 71
toId : 80Starting : Thread9
fromId : 81
toId : 90Starting : Thread10
fromId : 91
toId : 100Thread8 processing : 71 : user_71
Thread2 processing : 11 : user_11
Thread3 processing : 21 : user_21
Thread10 processing : 91 : user_91
Thread4 processing : 31 : user_31
Thread6 processing : 51 : user_51
Thread5 processing : 41 : user_41
Thread1 processing : 1 : user_1
Thread9 processing : 81 : user_81
Thread7 processing : 61 : user_61
Thread2 processing : 12 : user_12
Thread7 processing : 62 : user_62
Thread6 processing : 52 : user_52
Thread1 processing : 2 : user_2
Thread9 processing : 82 : user_82
...... 

该过程完成后,将创建 10 个 CSV 文件。

spring-batch-partitioner-afterusers.processed1-10.csv

 1,user_1,pass_1,20
2,user_2,pass_2,40
3,user_3,pass_3,70
4,user_4,pass_4,5
5,user_5,pass_5,52
6,user_6,pass_6,69
7,user_7,pass_7,48
8,user_8,pass_8,34
9,user_9,pass_9,62
10,user_10,pass_10,21 

6.混杂的

6.1 或者,你可以通过注释注入#{stepExecutionContext[name]}

UserProcessor.java - Annotation version

 package com.mkyong.processor;import org.springframework.batch.item.ItemProcessor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.mkyong.User;@Component("itemProcessor")
@Scope(value = "step")
public class UserProcessor implements ItemProcessor<User, User> {@Value("#{stepExecutionContext[name]}")private String threadName;@Overridepublic User process(User item) throws Exception {System.out.println(threadName + " processing : " + item.getId() + " : " + item.getUsername());return item;}} 

记住,启用弹簧组件自动扫描。

 <context:component-scan base-package="com.mkyong" /> 

6.2 数据库分区阅读器- MongoDB 示例。

job-partitioner.xml

 <bean id="mongoItemReader" class="org.springframework.batch.item.data.MongoItemReader"scope="step"><property name="template" ref="mongoTemplate" /><property name="targetType" value="com.mkyong.User" /><property name="query"value="{ 'id':{$gt:#{stepExecutionContext[fromId]}, $lte:#{stepExecutionContext[toId]} } }" /><property name="sort"><util:map id="sort"><entry key="id" value="" /></util:map></property></bean> 

完成了。

下载源代码

Download it - SpringBatch-Partitioner-Example.zip (31 KB)

参考

  1. 春季批量分割指南
  2. 分区器 JavaDoc
  3. ExecutionContext JavaDoc
  4. 维基:数据库分区

partition spring batch threads (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190708051040/https://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

春季批量教程

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/tutorials/spring-batch-tutorial/

spring batch model

图片来源:春天来源

Spring Batch 是一个用于批处理的开源框架——执行一系列的任务。Spring Batch 提供了用于读/写资源、事务管理、作业处理统计、作业重启和分区技术的类和 API,以处理大量数据。

以下 Spring 批处理教程和示例是通过以下方式测试的:

  1. 弹簧芯 3.2.2 .释放
  2. 春季批次 2.2.0 .发布

P.S Spring Batch 是 Spring 产品组合的一部分。

1.快速指南

一个简单的批处理作业,用命令行运行。

  • Spring Batch Hello World 示例
    关于 Spring Batch 的简短描述,并创建一个作业从 CSV 文件中读取数据,对其进行处理,并将其写入 XML 文件(JAXB)。
  • Spring Batch TaskletStep 示例
    示例在批处理作业完成后清理资源。
  • 用命令行运行 Spring 批处理作业 Runner
    用命令行运行 Spring 批处理作业。

2.项目读取器、项目处理器、项目写入器

几个例子展示了使用 Spring 批处理类来读/写资源(csv、xml 和数据库)。

  • Spring 批处理示例–CSV 文件到 MySQL 数据库
    从 CSV 文件中读取数据并将其写入 MySQL 数据库,作业元存储在数据库中。
  • Spring Batch Example–XML File To MongoDB database
    从 XML 文件(XStream)中读取数据,并将其写入 nosql 数据库 MongoDB,同时对批处理作业进行单元测试。
  • Spring 批处理示例–XML 文件到 CSV 文件
    从 XML 文件(JAXB2)中读取数据,用 ItemProcessor 处理并写入 CSV 文件。它还向您展示了如何通过 JAXB2 在 Date 和 BigDecimal 数据类型与 object 之间进行转换。
  • Spring 批处理示例——MySQL 数据库转 XML
    从 MySQL 数据库中读取数据并将其写入 XML 文件(XStream),同样使用了 jobParameters。
  • Spring Batch MultiResourceItemReader 示例
    一个 ItemReader 读取多个文件。

3.调度程序

使用调度程序框架运行批处理作业。

  • Spring Batch+Spring task scheduler 示例
    Spring TaskScheduler 安排一个批处理作业每 5 秒运行一次。
  • Spring Batch + Quartz 调度器示例
    集成 Quartz 来调度一个每 10 秒运行一次的批处理作业。

4.单元测试

  • Spring Batch 单元测试示例
    如何对一个批处理作业或单个步骤进行单元测试。

5.预先的

  • Spring Batch partitioner 示例
    多线程处理一系列数据。
  • Spring 批处理监听器示例
    示例拦截一个批处理作业的执行步骤。

6.春季批次常见问题

春批的一些常见问答。

  • 如何在 BeanWrapperFieldSetMapper 中转换日期
  • Spring Batch:对于参数= ,作业实例已经存在并且是完整的
  • Spring 批量元数据表不是自动创建的?
  • nosuchbean definitionexception:没有 JobLauncherTestUtils 类型的合格 bean
  • 在 BeanExpressionContext 类型的对象上找不到 jobParameters】

参考

  • 春批官网
  • 春季批次参考文件
  • 维基百科:春批
  • 春季批次样品

spring batch tutorials

春季批量单元测试示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-batch/spring-batch-unit-test-example/

在本教程中,我们将向您展示如何使用 jUnit 和 TestNG 框架对 Spring 批处理作业进行单元测试。对批处理作业进行单元测试,声明spring-batch-test.jar、@autowiredJobLauncherTestUtils,启动作业或步骤,并断言执行状态。

1.单元测试依赖关系

为了对 Spring 批处理进行单元测试,声明了以下依赖项:

pom.xml

 <!-- Spring Batch dependencies --><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-core</artifactId><version>2.2.0.RELEASE</version></dependency><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-infrastructure</artifactId><version>2.2.0.RELEASE</version></dependency><!-- Spring Batch unit test -->	<dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-test</artifactId><version>2.2.0.RELEASE</version></dependency><!-- Junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><!-- Testng --><dependency><groupId>org.testng</groupId><artifactId>testng</artifactId><version>6.8.5</version><scope>test</scope></dependency> 

2.春季批处理作业

一个简单的作业,稍后单元测试执行状态。

spring-batch-job.xml

 <!-- ...... --><batch:job id="testJob"><batch:step id="step1"><batch:tasklet><batch:chunk reader="xmlItemReader" writer="oracleItemWriter"commit-interval="1"></batch:chunk></batch:tasklet></batch:step></batch:job> 

3.jUnit 示例

启动作业并断言执行状态。

AppTest.java

 package com.mkyong;import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring/batch/jobs/spring-batch-job.xml","classpath:spring/batch/config/context.xml","classpath:spring/batch/config/test-context.xml"})
public class AppTest {@Autowiredprivate JobLauncherTestUtils jobLauncherTestUtils;@Testpublic void launchJob() throws Exception {//testing a jobJobExecution jobExecution = jobLauncherTestUtils.launchJob();//Testing a individual step//JobExecution jobExecution = jobLauncherTestUtils.launchStep("step1");assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());}
} 

P.S .假设context.xml声明了所有需要的 Spring batch 核心组件,如 jobRepository 等。

这个JobLauncherTestUtils必须手工声明。

test-context.xml

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"><!-- Spring should auto load this bean --><bean class="org.springframework.batch.test.JobLauncherTestUtils"/></beans> 

4.测试示例

TestNG 框架中的等效示例。

AppTest2.java

 package com.mkyong;import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.Test;@ContextConfiguration(locations = {"classpath:spring/batch/jobs/spring-batch-job.xml","classpath:spring/batch/config/context.xml","classpath:spring/batch/config/test-context.xml"})
public class AppTest2 extends AbstractTestNGSpringContextTests {@Autowiredprivate JobLauncherTestUtils jobLauncherTestUtils;@Testpublic void launchJob() throws Exception {JobExecution jobExecution = jobLauncherTestUtils.launchJob();Assert.assertEquals(jobExecution.getStatus(), BatchStatus.COMPLETED);}
} 

完成了。

下载源代码

Download it – SpringBatch-UnitTest-Example.zip (83 KB)

参考

  1. JobLauncherTestUtils JavaDoc
  2. 春季批量单元测试官方文档

junit spring batch testng unit test

Spring bean 参考示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-bean-reference-example/

在 Spring 中,bean 可以通过在相同或不同的 bean 配置文件中指定 bean 引用来“访问”彼此。

1.不同 XML 文件中的 Bean

如果您在不同的 XML 文件中引用一个 bean,您可以用一个'ref'标记、'bean'属性来引用它。

 <ref bean="someBean"/> 

在本例中,在'Spring-Common.xml'中声明的 bean " OutputHelper "可以访问'Spring-Output.xml'–"CsvOutputGenerator"或" JsonOutputGenerator "中的其他 bean,方法是使用 property 标记中的' ref '属性。

文件:Spring-Common.xml

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="OutputHelper" class="com.mkyong.output.OutputHelper"><property name="outputGenerator" ><ref bean="CsvOutputGenerator"/></property></bean></beans> 

文件:Spring-Output.xml

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator" /><bean id="JsonOutputGenerator" class="com.mkyong.output.impl.JsonOutputGenerator" /></beans> 

2.同一 XML 文件中的 Bean

如果在同一个 XML 文件中引用一个 bean,可以用'ref'标记、'local'属性引用它。

 <ref local="someBean"/> 

在本例中,'Spring-Common.xml'中声明的 bean " OutputHelper "可以互相访问" CsvOutputGenerator "或" JsonOutputGenerator "。

文件:Spring-Common.xml

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="OutputHelper" class="com.mkyong.output.OutputHelper"><property name="outputGenerator" ><ref local="CsvOutputGenerator"/></property></bean><bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator" /><bean id="JsonOutputGenerator" class="com.mkyong.output.impl.JsonOutputGenerator" /></beans> 

结论

实际上,“ref”标记可以访问相同或不同 XML 文件中的 bean,但是,为了项目的可读性,如果引用在相同 XML 文件中声明的 bean,则应该使用“local”属性。

spring

Spring bean 作用域示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-bean-scopes-examples/

在 Spring 中,bean 作用域用于决定哪种类型的 bean 实例应该从 Spring 容器返回给调用者。

支持 5 种类型的 bean 作用域:

  1. singleton——为每个 Spring IoC 容器返回一个 bean 实例
  2. 原型——每次请求时返回一个新的 bean 实例
  3. request——为每个 HTTP 请求返回一个 bean 实例。*
  4. session–为每个 HTTP 会话返回一个 bean 实例。*
  5. global session–为每个全局 HTTP 会话返回一个 bean 实例。*

在大多数情况下,您可能只处理 Spring 的核心范围——singleton 和 prototype,默认范围是 singleton。

*P.S 表示仅在 web 感知的 Spring 应用程序上下文的上下文中有效

单体 vs 原型

这里有一个例子向您展示 bean 作用域之间的区别: singletonprototype

 package com.mkyong.customer.services;public class CustomerService 
{String message;public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}
} 

1.单例示例

如果在 bean 配置文件中没有指定 bean 作用域,则默认为 singleton。

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="customerService" class="com.mkyong.customer.services.CustomerService" /></beans> 

运行它

 package com.mkyong.common;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.mkyong.customer.services.CustomerService;public class App 
{public static void main( String[] args ){ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"Spring-Customer.xml"});CustomerService custA = (CustomerService)context.getBean("customerService");custA.setMessage("Message by custA");System.out.println("Message : " + custA.getMessage());//retrieve it againCustomerService custB = (CustomerService)context.getBean("customerService");System.out.println("Message : " + custB.getMessage());}
} 

输出

 Message : Message by custA
Message : Message by custA 

因为 bean“customerService”在单例范围内,所以“custB”的第二次检索也将显示“custA”设置的消息,即使它是由新的 getBean()方法检索的。在 singleton 中,每个 Spring IoC 容器只有一个实例,不管用 getBean()检索多少次,它都将返回相同的实例。

2.原型示例

如果您想要一个新的“customerService”bean 实例,那么每次调用它时,请使用 prototype。

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="customerService" class="com.mkyong.customer.services.CustomerService" scope="prototype"/></beans> 

再运行一次

 Message : Message by custA
Message : null 

在 prototype 范围内,每个被调用的getBean()方法都有一个新的实例。

3.Bean 范围注释

您还可以使用注释来定义您的 bean 范围。

 package com.mkyong.customer.services;import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;@Service
@Scope("prototype")
public class CustomerService 
{String message;public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}
} 

启用自动组件扫描

 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd"><context:component-scan base-package="com.mkyong.customer" /></beans> 

下载源代码

Download It – Spring-Bean-Scopes-Example.zip (7 KB)

参考

  1. http://static . springsource . org/spring/docs/2.0 . x/reference/beans . html # beans-factory-scopes

Tags : spring

Spring Boot Ajax 示例

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-ajax-example/

本文将向您展示如何使用jQuery.ajaxSpring REST API发送 HTML 表单请求并返回 JSON 响应。

使用的工具:

  1. Spring Boot 1.5.1 .版本
  2. 弹簧 4.3.6 释放
  3. maven3
  4. jQuery
  5. 自举 3

Note
You may interest at this classic Spring MVC Ajax example

1.项目结构

一个标准的 Maven 项目结构。

spring boot ajax example

2.项目依赖性

一个正常的 Spring Boot 依赖和一些webjars资源。

pom.xml

 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>spring-boot-ajax-example</artifactId><packaging>jar</packaging><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.1.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><dependency><groupId>org.webjars</groupId><artifactId>jquery</artifactId><version>2.2.4</version></dependency><dependency><groupId>org.webjars</groupId><artifactId>bootstrap</artifactId><version>3.3.7</version></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project> 

3.Spring REST API

3.1 一个休息控制器,接受一个SearchCriteria并返回一个ResponseEntity

SearchController.java

 package com.mkyong.controller;import com.mkyong.model.AjaxResponseBody;
import com.mkyong.model.SearchCriteria;
import com.mkyong.model.User;
import com.mkyong.services.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;import javax.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;@RestController
public class SearchController {UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}@PostMapping("/api/search")public ResponseEntity<?> getSearchResultViaAjax(@Valid @RequestBody SearchCriteria search, Errors errors) {AjaxResponseBody result = new AjaxResponseBody();//If error, just return a 400 bad request, along with the error messageif (errors.hasErrors()) {result.setMsg(errors.getAllErrors().stream().map(x -> x.getDefaultMessage()).collect(Collectors.joining(",")));return ResponseEntity.badRequest().body(result);}List<User> users = userService.findByUserNameOrEmail(search.getUsername());if (users.isEmpty()) {result.setMsg("no user found!");} else {result.setMsg("success");}result.setResult(users);return ResponseEntity.ok(result);}} 

3.2 一些 POJO。

AjaxResponseBody.java

 package com.mkyong.model;import java.util.List;public class AjaxResponseBody {String msg;List<User> result;//getters and setters} 

User.java

 package com.mkyong.model;public class User {String username;String password;String email;public User(String username, String password, String email) {this.username = username;this.password = password;this.email = email;}//getters and setters
} 

3.3 验证。

SearchCriteria.java

 package com.mkyong.model;import org.hibernate.validator.constraints.NotBlank;public class SearchCriteria {@NotBlank(message = "username can't empty!")String username;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}
} 

3.4 初始化一些用户进行搜索的服务。

UserService.java

 package com.mkyong.services;import com.mkyong.model.User;
import org.springframework.stereotype.Service;import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;@Service
public class UserService {private List<User> users;// Love Java 8public List<User> findByUserNameOrEmail(String username) {List<User> result = users.stream().filter(x -> x.getUsername().equalsIgnoreCase(username)).collect(Collectors.toList());return result;}// Init some users for testing@PostConstructprivate void iniDataForTesting() {users = new ArrayList<User>();User user1 = new User("mkyong", "password111", "mkyong@yahoo.com");User user2 = new User("yflow", "password222", "yflow@yahoo.com");User user3 = new User("laplap", "password333", "mkyong@yahoo.com");users.add(user1);users.add(user2);users.add(user3);}} 

3.5 Spring Boot 起动机。

UserService.java

 package com.mkyong;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBootWebApplication {public static void main(String[] args) throws Exception {SpringApplication.run(SpringBootWebApplication.class, args);}} 

4.HTML 表单+ jQuery Ajax

4.1 一个简单的 HTML 表单,用 bootstrap 装饰。

ajax.html

 <!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"><head><title>Spring Boot ajax example</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/><link rel="stylesheet" type="text/css"href="webjars/bootstrap/3.3.7/css/bootstrap.min.css"/>
</head>
<body><nav class="navbar navbar-inverse"><div class="container"><div class="navbar-header"><a class="navbar-brand" href="#">Mkyong.com</a></div></div>
</nav><div class="container" style="min-height: 500px"><div class="starter-template"><h1>Spring Boot AJAX Example</h1><div id="feedback"></div><form class="form-horizontal" id="search-form"><div class="form-group form-group-lg"><label class="col-sm-2 control-label">Username</label><div class="col-sm-10"><input type="text" class="form-control" id="username"/></div></div><div class="form-group"><div class="col-sm-offset-2 col-sm-10"><button type="submit" id="bth-search"class="btn btn-primary btn-lg">Search</button></div></div></form></div></div><div class="container"><footer><p>© <a href="http://www.mkyong.com">Mkyong.com</a> 2017</p></footer>
</div><script type="text/javascript"src="webjars/jquery/2.2.4/jquery.min.js"></script><script type="text/javascript" src="js/main.js"></script></body>
</html> 

4.2 获取 HTML 表单,通过JSON.stringify将搜索条件转换成 JSON 格式,通过jQuery.ajax发送 POST 请求

main.js

 $(document).ready(function () {$("#search-form").submit(function (event) {//stop submit the form, we will post it manually.event.preventDefault();fire_ajax_submit();});});function fire_ajax_submit() {var search = {}search["username"] = $("#username").val();$("#btn-search").prop("disabled", true);$.ajax({type: "POST",contentType: "application/json",url: "/api/search",data: JSON.stringify(search),dataType: 'json',cache: false,timeout: 600000,success: function (data) {var json = "<h4>Ajax Response</h4>&lt;pre&gt;"+ JSON.stringify(data, null, 4) + "&lt;/pre&gt;";$('#feedback').html(json);console.log("SUCCESS : ", data);$("#btn-search").prop("disabled", false);},error: function (e) {var json = "<h4>Ajax Response</h4>&lt;pre&gt;"+ e.responseText + "&lt;/pre&gt;";$('#feedback').html(json);console.log("ERROR : ", e);$("#btn-search").prop("disabled", false);}});} 

完成了。

5.演示

5.1 启动 Spring Boot

Terminal

 $ mvn spring-boot:run.   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v1.5.1.RELEASE)2017-02-03 14:56:36 DEBUG com.mkyong.SpringBootWebApplication - Running with Spring Boot v1.5.1.RELEASE, Spring v4.3.6.RELEASE
2017-02-03 14:56:36 INFO  com.mkyong.SpringBootWebApplication - No active profile set, falling back to default profiles: default
2017-02-03 14:56:39 INFO  com.mkyong.SpringBootWebApplication - Started SpringBootWebApplication in 2.828 seconds (JVM running for 3.295) 

5.2 访问 http://localhost:8080/

5.3 如果用户名为空!

5.4 如果找不到用户名!

5.5 如果找到用户名!

6.下载源代码

Download – spring-boot-ajax-example.zip (10 KB)

参考

  1. Spring IO——构建 RESTful Web 服务
  2. MDN–JSON . stringify()
  3. Spring 4 MVC Ajax Hello World 示例

Spring Boot @配置属性示例

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-configurationproperties-example/

Spring Boot @ConfigurationProperties

Spring Boot @ConfigurationProperties让开发者可以轻松地将整个.propertiesyml文件映射成一个对象。

PS 用 Spring Boot 2.1.2.RELEASE 测试

1.@值

1.1 通常情况下,我们使用@Value来逐个注入.properties的值,这对于小且结构简单的.properties文件很好。举个例子,

global.properties

 email=test@mkyong.com
thread-pool=12 

GlobalProperties.java

 @Component
@PropertySource("classpath:global.properties")
public class GlobalProperties {@Value("${thread-pool}")private int threadPool;@Value("${email}")private String email;//getters and setters} 

1.2@ConfigurationProperties中的等价物

GlobalProperties.java

 import org.springframework.boot.context.properties.ConfigurationProperties;@Component
@PropertySource("classpath:global.properties")
@ConfigurationProperties
public class GlobalProperties {private int threadPool;private String email;//getters and setters} 

2.@配置属性

2.1 查看下面的复杂结构.propertiesyml文件,我们如何通过@Value映射值?

application.properties

 #Logging
logging.level.org.springframework.web=ERROR
logging.level.com.mkyong=DEBUG#Global
email=test@mkyong.com
thread-pool=10#App
app.menus[0].title=Home
app.menus[0].name=Home
app.menus[0].path=/
app.menus[1].title=Login
app.menus[1].name=Login
app.menus[1].path=/loginapp.compiler.timeout=5
app.compiler.output-folder=/temp/app.error=/error/ 

或 YAML 的同等机构。

application.yml

 logging:level:org.springframework.web: ERRORcom.mkyong: DEBUG
email: test@mkyong.com
thread-pool: 10
app:menus:- title: Homename: Homepath: /- title: Loginname: Loginpath: /logincompiler:timeout: 5output-folder: /temp/error: /error/ 

Note
@ConfigurationProperties supports both .properties and .yml file.

2.2 @ConfigurationProperties前来救援:

AppProperties.java

 package com.mkyong;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;@Component
@ConfigurationProperties("app") // prefix app, find app.* values
public class AppProperties {private String error;private List<Menu> menus = new ArrayList<>();private Compiler compiler = new Compiler();public static class Menu {private String name;private String path;private String title;//getters and setters@Overridepublic String toString() {return "Menu{" +"name='" + name + '\'' +", path='" + path + '\'' +", title='" + title + '\'' +'}';}}public static class Compiler {private String timeout;private String outputFolder;//getters and setters@Overridepublic String toString() {return "Compiler{" +"timeout='" + timeout + '\'' +", outputFolder='" + outputFolder + '\'' +'}';}}//getters and setters
} 

GlobalProperties.java

 package com.mkyong;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component
@ConfigurationProperties // no prefix, find root level values.
public class GlobalProperties {private int threadPool;private String email;//getters and setters
} 

3.@配置属性验证

这个@ConfigurationProperties支持 JSR-303 bean 验证。

3.1 在@ConfigurationProperties类上添加@Validated,在我们想要验证的字段上添加javax.validation注释。

GlobalProperties.java

 package com.mkyong;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;@Component
@ConfigurationProperties
@Validated
public class GlobalProperties {@Max(5)@Min(0)private int threadPool;@NotEmptyprivate String email;//getters and setters
} 

3.2 设置线程池=10

application.properties

 #Global
email=test@mkyong.com
thread-pool=10 

3.3 启动 Spring Boot,我们将点击以下错误信息:

Console

 ***************************
APPLICATION FAILED TO START
***************************Description:Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under '' to com.mkyong.GlobalProperties failed:Property: .threadPoolValue: 10Origin: class path resource [application.properties]:7:13Reason: must be less than or equal to 5Action:Update your application's configuration 

4.演示

 $ git clone https://github.com/mkyong/spring-boot.git
$ cd externalize-config-properties-yaml
$ mvn spring-boot:runaccess localhost:8080 

demoNote
For more detail, please refer to this official Spring Boot Externalized Configuration

下载源代码

$ git clone https://github.com/mkyong/spring-boot.git
$ cd externalize-config-properties-yaml
$ mvn spring-boot:run

访问本地主机:8080

参考

  • Spring Boot–外部化配置
  • Spring @PropertySource 示例
  • JSR 303: Bean 验证

Spring Boot–在嵌入式 Tomcat 中配置 maxSwallowSize

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-configure-maxswallowsize-in-embedded-tomcat/

在 Spring Boot,你不能通过通用应用属性配置嵌入式 Tomcat maxSwallowSize,没有像server.tomcat.*.maxSwallowSize这样的选项

解决办法

要修复它,您需要声明一个TomcatEmbeddedServletContainerFactory bean,并像这样配置maxSwallowSize:

 //...
import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;private int maxUploadSizeInMb = 10 * 1024 * 1024; // 10 MB@Beanpublic TomcatEmbeddedServletContainerFactory tomcatEmbedded() {TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {// connector other settings...// configure maxSwallowSizeif ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {// -1 means unlimited, accept bytes((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);}});return tomcat;} 

参考

  1. Spring 文件上传和连接重置问题
  2. 常用应用属性
  3. Spring Boot 文件上传错误处理(Japanase)

connection reset file upload spring boot tomcat (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190309055300/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

Spring Boot–自定义横幅示例

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-custom-banner-example/

这篇文章向你展示了如何用你的自定义横幅替换下面默认的 Spring 横幅。

 .   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v1.5.1.RELEASE) 

解决办法

1.要在 Spring Boot 应用程序中添加自定义横幅,请创建一个banner.txt文件,并将其放入resources文件夹。

2.回顾一下banner.txt的内容,这个 ASCII Art 是由这个 ASCII Art Java 示例创建的,ANSI 颜色是手动添加的。

src/main/resources/banner.txt

 ${Ansi.RED}                  $$$        $$$$$      $$$$         $$$$     $$$$$
${Ansi.GREEN}                  $$$       $$$$$$$     $$$$         $$$$    $$$$$$$
${Ansi.BLUE}                  $$$       $$$$$$$     $$$$$       $$$$$    $$$$$$$
${Ansi.RED}                  $$$       $$$$$$$      $$$$       $$$$     $$$$$$$
${Ansi.GREEN}                  $$$      $$$$ $$$$     $$$$$     $$$$$    $$$$ $$$$
${Ansi.BLUE}                  $$$      $$$$ $$$$      $$$$     $$$$     $$$$ $$$$
${Ansi.RED}                  $$$     $$$$$ $$$$$     $$$$     $$$$    $$$$$ $$$$$
${Ansi.GREEN}                  $$$     $$$$   $$$$     $$$$$   $$$$$    $$$$   $$$$
${Ansi.BLUE}                  $$$     $$$$   $$$$      $$$$   $$$$     $$$$   $$$$
${Ansi.RED}                  $$$    $$$$$   $$$$$     $$$$$ $$$$$    $$$$$   $$$$$
${Ansi.GREEN}                  $$$    $$$$$$$$$$$$$      $$$$ $$$$     $$$$$$$$$$$$$
${Ansi.BLUE}          $$$$   $$$$    $$$$$$$$$$$$$      $$$$ $$$$     $$$$$$$$$$$$$
${Ansi.RED}          $$$$   $$$$   $$$$$$$$$$$$$$$      $$$$$$$     $$$$$$$$$$$$$$$
${Ansi.GREEN}          $$$$$ $$$$$   $$$$       $$$$      $$$$$$$     $$$$       $$$$
${Ansi.BLUE}          $$$$$$$$$$$  $$$$$       $$$$$     $$$$$$$    $$$$$       $$$$$
${Ansi.RED}           $$$$$$$$$   $$$$         $$$$      $$$$$     $$$$         $$$$
${Ansi.GREEN}            $$$$$$$    $$$$         $$$$      $$$$$     $$$$         $$$$${Ansi.RED} :: Spring Boot${spring-boot.formatted-version} :: ${Ansi.DEFAULT} 

3.启动 Spring Boot,将显示以下输出:

参考

  1. Spring Boot——定制横幅
  2. ASCII Art Java 示例

Spring Boot-将 WAR 文件部署到 Tomcat

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-deploy-war-file-to-tomcat/

在本文中,我们将向您展示如何将 Spring Boot 战争文件部署到 Tomcat servlet 容器中。

对于 Spring Boot 战争的部署,你需要做三个步骤:

  1. 扩展 SpringBootServletInitializer
  2. 将嵌入式 servlet 容器标记为已提供。
  3. 将包装更新到 war

已测试

  1. Spring Boot 1.4.2 版本
  2. Tomcat 8.5.9
  3. maven3

Note
In Spring Boot, the final executable JAR file with embedded server solution may not suitable in all production environments, especially the deployment team (a team with good knowledge of server optimization and monitoring skills, but lack of, the development experience), they want full control of the server, and they don’t touch code.

1.扩展 SpringBootServletInitializer

使现有的@SpringBootApplication类扩展SpringBootServletInitializer

1.1 经典的 Spring Boot JAR 部署。(更新此文件以支持 WAR 部署)

SpringBootWebApplication.java

 import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBootWebApplication {public static void main(String[] args) throws Exception {SpringApplication.run(SpringBootWebApplication.class, args);}} 

1.2 Spring Boot 战争部署。

SpringBootWebApplication.java

 import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;@SpringBootApplication
public class SpringBootWebApplication extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(SpringBootWebApplication.class);}public static void main(String[] args) throws Exception {SpringApplication.run(SpringBootWebApplication.class, args);}}/*@SpringBootApplication
public class SpringBootWebApplication {public static void main(String[] args) throws Exception {SpringApplication.run(SpringBootWebApplication.class, args);}}*/ 

如果您为部署创建一个额外的SpringBootWebApplication类,一定要告诉 Spring Boot 要启动哪个主类:

pom.xml

 <properties><start-class>com.mkyong.NewSpringBootWebApplicationForWAR</start-class></properties> 

读读这个——Spring Boot——从哪个主班开始

2.将嵌入式 servlet 容器标记为已提供

pom.xml

 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- marked the embedded servlet container as provided --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency></dependencies> 

3.将包装更新到 war

pom.xml

 <packaging>war</packaging> 

完成后,mvn package并将$project/target/xxx.war复制到 Tomcat 进行部署。

4.完整示例——Spring Boot 战争+ Tomcat 部署

4.1 以这个 Spring Boot 百里香为例,手动更新并部署到 Tomcat。

4.2 更新现有的SpringBootWebApplication并使其扩展SpringBootServletInitializer

pom.xml

 package com.mkyong;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;@SpringBootApplication
public class SpringBootWebApplication extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(SpringBootWebApplication.class);}public static void main(String[] args) throws Exception {SpringApplication.run(SpringBootWebApplication.class, args);}} 

4.3 将包装更新为war,并按规定标记spring-boot-starter-tomcat

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>spring-boot-web-thymeleaf</artifactId><packaging>war</packaging><name>Spring Boot Web Thymeleaf Example</name><description>Spring Boot Web Thymeleaf Example</description><url>https://www.mkyong.com</url><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.4.2.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- marked the embedded servlet container as provided --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency><!-- hot swapping, disable cache for template, enable live reload --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><!-- Optional, for bootstrap --><dependency><groupId>org.webjars</groupId><artifactId>bootstrap</artifactId><version>3.3.7</version></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project> 

4.4 这是可选的,稍后更新contextPath/mkyong进行演示。完成了。准备战争部署。

application.properties

 welcome.message: Hello Mkyongserver.contextPath=/mkyong 

4.5 获取 Tomcat 并部署 WAR 文件。

Mac OS X : Terminal

 # Get Tomcat 8.5.9
spring-boot-project$ curl -O  http://www-us.apache.org/dist/tomcat/tomcat-8/v8.5.9/bin/apache-tomcat-8.5.9.tar.gz% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed
100 9112k  100 9112k    0     0   799k      0  0:00:11  0:00:11 --:--:-- 1348k# Extract it
$ tar -xvzf apache-tomcat-8.5.9.tar.gz # Maven clean and package everything into a WAR file.
$ mvn clean package# Copy WAR to Tomcat/webapp, renamed to mkyong.war
# By default, Tomcat take the war file name as the context path
$ cp target/spring-boot-web-thymeleaf-1.0.war apache-tomcat-8.5.9/webapps/mkyong.war# Start Tomcat
$ ./apache-tomcat-8.5.9/bin/startup.sh 
Using CATALINA_BASE:   /Users/mkyong/projects/spring-boot-web-thymeleaf/apache-tomcat-8.5.9
Using CATALINA_HOME:   /Users/mkyong/projects/spring-boot-web-thymeleaf/apache-tomcat-8.5.9
Using CATALINA_TMPDIR: /Users/mkyong/projects/spring-boot-web-thymeleaf/apache-tomcat-8.5.9/temp
Using JRE_HOME:        /Library/Java/JavaVirtualMachines/jdk1.8.0_74.jdk/Contents/Home
Using CLASSPATH:       /Users/mkyong/projects/spring-boot-web-thymeleaf/apache-tomcat-8.5.9/bin/bootstrap.jar:
/Users/mkyong/projects/spring-boot-web-thymeleaf/apache-tomcat-8.5.9/bin/tomcat-juli.jar
Tomcat started. 

4.6 访问http://localhost:8080/mkyong/

spring-boot-tomcat-deployment

4.7 搞定。关闭 Tomcat。

Mac OS X : Terminal

 $ ./apache-tomcat-8.5.9/bin/shutdown.sh 

下载源代码

Download – spring-boot-war-tomcat.zip (13 KB)

参考

  1. Spring Boot–传统部署
  2. Spring Boot Hello World 示例–百里香叶
  3. 如何在 Debian 上安装 Apache Tomcat 8

deployment spring boot tomcat war

Spring Boot 文件上传示例–Ajax 和 REST

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-file-upload-example-ajax-and-rest/

这篇文章展示了如何使用 Ajax 请求在 Spring Boot web 应用程序(REST 结构)中上传文件。

本文中使用的工具:

  1. Spring Boot 1.4.3 版本
  2. 弹簧 4.3.5 .释放
  3. 百里香叶
  4. jQuery (webjars)
  5. 专家
  6. 嵌入式 Tomcat 8.5.6
  7. 谷歌 Chrome 浏览器(网络检查)

1.项目结构

一个标准的 Maven 项目结构。

spring-boot-file-upload-ajax-directory-1 ## 2.项目依赖性

为 HTML 格式的 Ajax 请求声明一个额外的jQuery webjar 依赖项。

pom.xml

 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>spring-boot-file-upload</artifactId><packaging>jar</packaging><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.4.3.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- hot swapping, disable cache for template, enable live reload --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><dependency><groupId>org.webjars</groupId><artifactId>jquery</artifactId><version>2.2.4</version></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project> 

3.文件上传

为了支持 Ajax 请求和响应,最简单的解决方案是返回一个ResponseEntity

3.1 以下示例演示了上传文件的三种可能方式:

  1. 单个文件上传-MultipartFile
  2. 多文件上传-MultipartFile[]
  3. 将地图文件上传到模型–@ModelAttribute

RestUploadController.java

 package com.mkyong.controller;import com.mkyong.model.UploadModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;@RestController
public class RestUploadController {private final Logger logger = LoggerFactory.getLogger(RestUploadController.class);//Save the uploaded file to this folderprivate static String UPLOADED_FOLDER = "F://temp//";// 3.1.1 Single file upload@PostMapping("/api/upload")// If not @RestController, uncomment this//@ResponseBodypublic ResponseEntity<?> uploadFile(@RequestParam("file") MultipartFile uploadfile) {logger.debug("Single file upload!");if (uploadfile.isEmpty()) {return new ResponseEntity("please select a file!", HttpStatus.OK);}try {saveUploadedFiles(Arrays.asList(uploadfile));} catch (IOException e) {return new ResponseEntity<>(HttpStatus.BAD_REQUEST);}return new ResponseEntity("Successfully uploaded - " +uploadfile.getOriginalFilename(), new HttpHeaders(), HttpStatus.OK);}// 3.1.2 Multiple file upload@PostMapping("/api/upload/multi")public ResponseEntity<?> uploadFileMulti(@RequestParam("extraField") String extraField,@RequestParam("files") MultipartFile[] uploadfiles) {logger.debug("Multiple file upload!");// Get file nameString uploadedFileName = Arrays.stream(uploadfiles).map(x -> x.getOriginalFilename()).filter(x -> !StringUtils.isEmpty(x)).collect(Collectors.joining(" , "));if (StringUtils.isEmpty(uploadedFileName)) {return new ResponseEntity("please select a file!", HttpStatus.OK);}try {saveUploadedFiles(Arrays.asList(uploadfiles));} catch (IOException e) {return new ResponseEntity<>(HttpStatus.BAD_REQUEST);}return new ResponseEntity("Successfully uploaded - "+ uploadedFileName, HttpStatus.OK);}// 3.1.3 maps html form to a Model@PostMapping("/api/upload/multi/model")public ResponseEntity<?> multiUploadFileModel(@ModelAttribute UploadModel model) {logger.debug("Multiple file upload! With UploadModel");try {saveUploadedFiles(Arrays.asList(model.getFiles()));} catch (IOException e) {return new ResponseEntity<>(HttpStatus.BAD_REQUEST);}return new ResponseEntity("Successfully uploaded!", HttpStatus.OK);}//save fileprivate void saveUploadedFiles(List<MultipartFile> files) throws IOException {for (MultipartFile file : files) {if (file.isEmpty()) {continue; //next pls}byte[] bytes = file.getBytes();Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());Files.write(path, bytes);}}
} 

3.2 上述示例 3.1.3 的简单模型—@ModelAttribute

UploadModel.java

 package com.mkyong.model;import org.springframework.web.multipart.MultipartFile;public class UploadModel {private String extraField;private MultipartFile[] files;//getters and setters
} 

4.风景

用于多文件上传的 HTML 表单。

upload.html

 <!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body><h1>Spring Boot - Multiple file upload example - AJAX</h1><form method="POST" enctype="multipart/form-data" id="fileUploadForm"><input type="text" name="extraField"/><br/><br/><input type="file" name="files"/><br/><br/><input type="file" name="files"/><br/><br/><input type="submit" value="Submit" id="btnSubmit"/>
</form><h1>Ajax Post Result</h1>
<pre><span id="result"></span>
</pre><script type="text/javascript"src="webjars/jquery/2.2.4/jquery.min.js"></script><script type="text/javascript" src="js/main.js"></script></body>
</html> 

5.jQuery–Ajax 请求

jQuery 通过表单#id获取表单,并通过 Ajax 请求发送多部分表单数据。

resources/static/js/main.js

 $(document).ready(function () {$("#btnSubmit").click(function (event) {//stop submit the form, we will post it manually.event.preventDefault();fire_ajax_submit();});});function fire_ajax_submit() {// Get formvar form = $('#fileUploadForm')[0];var data = new FormData(form);data.append("CustomField", "This is some extra data, testing");$("#btnSubmit").prop("disabled", true);$.ajax({type: "POST",enctype: 'multipart/form-data',url: "/api/upload/multi",data: data,//http://api.jquery.com/jQuery.ajax///https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_ObjectsprocessData: false, //prevent jQuery from automatically transforming the data into a query stringcontentType: false,cache: false,timeout: 600000,success: function (data) {$("#result").text(data);console.log("SUCCESS : ", data);$("#btnSubmit").prop("disabled", false);},error: function (e) {$("#result").text(e.responseText);console.log("ERROR : ", e);$("#btnSubmit").prop("disabled", false);}});} 

6.异常处理程序

为了处理来自 Ajax 请求的异常,只需扩展ResponseEntityExceptionHandler并返回一个ResponseEntity

RestGlobalExceptionHandler.java

 package com.mkyong.exception;import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;import javax.servlet.http.HttpServletRequest;//http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-error-handling
@ControllerAdvice
public class RestGlobalExceptionHandler extends ResponseEntityExceptionHandler {// Catch file size exceeded exception!@ExceptionHandler(MultipartException.class)@ResponseBodyResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {HttpStatus status = getStatus(request);return new ResponseEntity(ex.getMessage(), status);// example//return new ResponseEntity("success", responseHeaders, HttpStatus.OK);}private HttpStatus getStatus(HttpServletRequest request) {Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");if (statusCode == null) {return HttpStatus.INTERNAL_SERVER_ERROR;}return HttpStatus.valueOf(statusCode);}} 

7.演示

用默认的嵌入式 Tomcat mvn spring-boot:run启动 Spring Boot。

7.1 访问 http://localhost:8080/ ,选择几个文件,点击提交,启动 ajax 请求。

spring-boot-file-upload-ajax-1

7.2 Google Chrome,在“网络检查”中查看请求和响应

spring-boot-file-upload-ajax-2

7.3 谷歌浏览器,“请求有效载荷”

spring-boot-file-upload-ajax-3

8.卷曲测试

使用cURL命令进行更多测试。

8.1 测试单个文件上传。

Terminal

 $ curl -F file=@"f:\\data.txt" http://localhost:8080/api/upload/
Successfully uploaded - data.txt 

8.2 测试多文件上传。

Terminal

 $ curl -F extraField="abc" -F files=@"f://data.txt" -F files=@"f://data2.txt"  http://localhost:8080/api/upload/multi/
Successfully uploaded - data.txt , data2.txt 

8.3 测试多个文件上传,映射到模型。

Terminal

 $ curl -F extraField="abc" -F files=@"f://data.txt" -F files=@"f://data2.txt"  http://localhost:8080/api/upload/multi/model
Successfully uploaded! 

8.4 测试一个大的电影文件(100MB),会显示以下错误信息。

Terminal

 $ curl -F file=@"F://movies//300//Sample.mkv"  http://localhost:8080/api/upload/
Attachment size exceeds the allowable limit! (10MB) 

9.cURL 测试+自定义错误对象

9.1 创建一个对象来存储错误详细信息。

CustomError.java

 package com.mkyong.exception;public class CustomError {String errCode;String errDesc;public CustomError(String errCode, String errDesc) {this.errCode = errCode;this.errDesc = errDesc;}//getters and setters
} 

9.2 更新全局异常处理程序以支持CustomError对象。

RestGlobalExceptionHandler.java

 package com.mkyong.exception;import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;import javax.servlet.http.HttpServletRequest;@ControllerAdvice
public class RestGlobalExceptionHandler extends ResponseEntityExceptionHandler {@ExceptionHandler(MultipartException.class)@ResponseBodyResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {HttpStatus status = getStatus(request);return new ResponseEntity(new CustomError("0x000123", "Attachment size exceeds the allowable limit! (10MB)"), status);//return new ResponseEntity("Attachment size exceeds the allowable limit! (10MB)", status);}private HttpStatus getStatus(HttpServletRequest request) {Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");if (statusCode == null) {return HttpStatus.INTERNAL_SERVER_ERROR;}return HttpStatus.valueOf(statusCode);}} 

9.3 cURL 再次上传大文件。

Terminal

 $ curl -F file=@"F://movies//300//Sample.mkv"  http://localhost:8080/api/upload/{"errCode":"0x000123","errDesc":"Attachment size exceeds the allowable limit! (10MB)"} 

完成了。欢迎反馈。

10.下载源代码

Download – spring-boot-file-upload-ajax-rest.zip (11 KB)

参考

  1. Spring Boot–错误处理
  2. Spring Boot 文件上传示例
  3. Spring MVC 文件上传示例
  4. Spring Boot Hello World 示例–百里香叶
  5. 维基百科–卷曲
  6. jQuery.ajax()
  7. MDN–使用表单数据对象

ajax curl file upload jquery multipart rest spring boot

Spring Boot 文件上传示例

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-file-upload-example/

这篇文章向你展示了如何在 Spring Boot 网络应用程序中上传文件。

使用的工具:

  1. Spring Boot 1.4.3 版本
  2. 弹簧 4.3.5 .释放
  3. 百里香叶
  4. 专家
  5. 嵌入式 Tomcat 8.5.6

1.项目结构

标准项目结构。

spring-boot-file-upload-example-directory

2.项目依赖性

春季启动依赖,不需要额外的文件上传库。

pom.xml

 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>spring-boot-file-upload</artifactId><packaging>jar</packaging><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.4.3.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- hot swapping, disable cache for template, enable live reload --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project> 

3.文件上传示例

春季开机文件上传,零配置。

3.1 在控制器中,将上传的文件映射到MultipartFile

UploadController.java

 package com.mkyong.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;@Controller
public class UploadController {//Save the uploaded file to this folderprivate static String UPLOADED_FOLDER = "F://temp//";@GetMapping("/")public String index() {return "upload";}@PostMapping("/upload") // //new annotation since 4.3public String singleFileUpload(@RequestParam("file") MultipartFile file,RedirectAttributes redirectAttributes) {if (file.isEmpty()) {redirectAttributes.addFlashAttribute("message", "Please select a file to upload");return "redirect:uploadStatus";}try {// Get the file and save it somewherebyte[] bytes = file.getBytes();Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());Files.write(path, bytes);redirectAttributes.addFlashAttribute("message","You successfully uploaded '" + file.getOriginalFilename() + "'");} catch (IOException e) {e.printStackTrace();}return "redirect:/uploadStatus";}@GetMapping("/uploadStatus")public String uploadStatus() {return "uploadStatus";}} 

3.2 在百里香里,只是一些普通的 HTML 文件标签。

upload.jsp

 <!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body><h1>Spring Boot file upload example</h1><form method="POST" action="/upload" enctype="multipart/form-data"><input type="file" name="file" /><br/><br/><input type="submit" value="Submit" />
</form></body>
</html> 

3.3 上传状态的另一个页面

uploadStatus.jsp

 <!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body><h1>Spring Boot - Upload Status</h1><div th:if="${message}"><h2 th:text="${message}"/>
</div></body>
</html> 

4.超过最大上传大小

为了处理超过最大上传大小的异常,声明一个@ControllerAdvice并捕捉MultipartException

GlobalExceptionHandler.java

 package com.mkyong.controller;import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;@ControllerAdvice
public class GlobalExceptionHandler {//https://jira.spring.io/browse/SPR-14651//Spring 4.3.5 supports RedirectAttributes@ExceptionHandler(MultipartException.class)public String handleError1(MultipartException e, RedirectAttributes redirectAttributes) {redirectAttributes.addFlashAttribute("message", e.getCause().getMessage());return "redirect:/uploadStatus";}/* Spring < 4.3.5@ExceptionHandler(MultipartException.class)public String handleError2(MultipartException e) {return "redirect:/errorPage";}*/} 

5.Tomcat 连接重置

如果你部署到 Tomcat,配置maxSwallowSize来避免这个 Tomcat 连接重置问题。对于嵌入式 Tomcat,声明如下的TomcatEmbeddedServletContainerFactory:

SpringBootWebApplication.java

 package com.mkyong;import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;@SpringBootApplication
public class SpringBootWebApplication {private int maxUploadSizeInMb = 10 * 1024 * 1024; // 10 MBpublic static void main(String[] args) throws Exception {SpringApplication.run(SpringBootWebApplication.class, args);}//Tomcat large file upload connection reset//http://www.mkyong.com/spring/spring-file-upload-and-connection-reset-issue/@Beanpublic TomcatEmbeddedServletContainerFactory tomcatEmbedded() {TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {//-1 means unlimited((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);}});return tomcat;}} 

6.多部分文件大小

默认情况下,Spring Boot 最大文件上传大小为 1MB,您可以通过以下应用程序属性配置该值:

application.properties

 #http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#common-application-properties
#search multipart
spring.http.multipart.max-file-size=10MB
spring.http.multipart.max-request-size=10MB 

7.演示

用默认的嵌入式 Tomcat mvn spring-boot:run启动 Spring Boot。

Terminal

 $ mvn spring-boot:run.   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v1.4.3.RELEASE)2017-01-21 07:48:53 INFO  com.mkyong.SpringBootWebApplication - Starting SpringBootWebApplication on MKYONG-WIN10 with PID 2384 (E:\spring-boot-file-upload\target\classes started by mkyong in E:\spring-boot-file-upload)
2017-01-21 07:48:53 DEBUG com.mkyong.SpringBootWebApplication - Running with Spring Boot v1.4.3.RELEASE, Spring v4.3.5.RELEASE
2017-01-21 07:48:53 INFO  com.mkyong.SpringBootWebApplication - No active profile set, falling back to default profiles: default
2017-01-21 07:48:55 INFO  com.mkyong.SpringBootWebApplication - Started SpringBootWebApplication in 2.54 seconds (JVM running for 2.924) 

7.1 访问 http://localhost:8080/

spring-boot-file-upload-example

7.2 选择一个文件并上传。

spring-boot-file-upload-example-2

7.3 选择一个大于 10mb 的文件,您将访问此页面。

spring-boot-file-upload-example-3

8.下载源代码

Download – spring-boot-file-upload-example.zip (7 KB)

参考

  1. Spring Boot 常用应用属性
  2. Spring MVC 文件上传示例
  3. Spring @ExceptionHandler 和 RedirectAttributes
  4. Spring Boot Hello World 示例–百里香叶

Spring Boot Hello World 示例 JSP

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-hello-world-example-jsp/

一个 Spring Boot 的 web 应用例子,使用embedded Tomcat + JSP template,并打包成一个可执行的 WAR 文件。

使用的技术:

  1. Spring Boot 1.4.2 版本
  2. 弹簧 4.3.4 释放
  3. Tomcat Embed 8.5.6
  4. maven3
  5. Java 8

1.项目目录

手动创建以下文件夹:

spring-boot-web-jsp-project-directory

2.项目相关性

Maven 例子。阅读注释,了解更多信息。

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>spring-boot-web-jsp</artifactId><packaging>war</packaging><name>Spring Boot Web JSP Example</name><description>Spring Boot Web JSP Example</description><url>https://www.mkyong.com</url><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.4.2.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><!-- This is a web application --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Tomcat embedded container--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency><!-- JSTL for JSP --><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><!-- Need this to compile JSP --><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><scope>provided</scope></dependency><!-- Need this to compile JSP, tomcat-embed-jasper version is not working, no idea why --><dependency><groupId>org.eclipse.jdt.core.compiler</groupId><artifactId>ecj</artifactId><version>4.6.1</version><scope>provided</scope></dependency><!-- Optional, test for static content, bootstrap CSS--><dependency><groupId>org.webjars</groupId><artifactId>bootstrap</artifactId><version>3.3.7</version></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project> 

显示项目部门:

 $ mvn dependency:tree[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Spring Boot Web JSP Example 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.10:tree (default-cli) @ spring-boot-web-jsp ---
[INFO] org.springframework.boot:spring-boot-web-jsp:war:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:1.4.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:1.4.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot:jar:1.4.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:1.4.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:1.4.2.RELEASE:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.1.7:compile
[INFO] |  |  |  |  +- ch.qos.logback:logback-core:jar:1.1.7:compile
[INFO] |  |  |  |  \- org.slf4j:slf4j-api:jar:1.7.21:compile
[INFO] |  |  |  +- org.slf4j:jcl-over-slf4j:jar:1.7.21:compile
[INFO] |  |  |  +- org.slf4j:jul-to-slf4j:jar:1.7.21:compile
[INFO] |  |  |  \- org.slf4j:log4j-over-slf4j:jar:1.7.21:compile
[INFO] |  |  +- org.springframework:spring-core:jar:4.3.4.RELEASE:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.17:runtime
[INFO] |  +- org.hibernate:hibernate-validator:jar:5.2.4.Final:compile
[INFO] |  |  +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO] |  |  +- org.jboss.logging:jboss-logging:jar:3.3.0.Final:compile
[INFO] |  |  \- com.fasterxml:classmate:jar:1.3.3:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.4:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.4:compile
[INFO] |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.8.4:compile
[INFO] |  +- org.springframework:spring-web:jar:4.3.4.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-aop:jar:4.3.4.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-beans:jar:4.3.4.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-context:jar:4.3.4.RELEASE:compile
[INFO] |  \- org.springframework:spring-webmvc:jar:4.3.4.RELEASE:compile
[INFO] |     \- org.springframework:spring-expression:jar:4.3.4.RELEASE:compile
[INFO] +- org.springframework.boot:spring-boot-starter-tomcat:jar:1.4.2.RELEASE:provided
[INFO] |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.6:provided
[INFO] |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:8.5.6:provided
[INFO] |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.5.6:provided
[INFO] +- javax.servlet:jstl:jar:1.2:compile
[INFO] +- org.apache.tomcat.embed:tomcat-embed-jasper:jar:8.5.6:provided
[INFO] +- org.eclipse.jdt.core.compiler:ecj:jar:4.6.1:provided
[INFO] \- org.webjars:bootstrap:jar:3.3.7:compile
[INFO]    \- org.webjars:jquery:jar:1.11.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.327 s
[INFO] Finished at: 2016-11-28T16:57:00+08:00
[INFO] Final Memory: 20M/309M
[INFO] ------------------------------------------------------------------------ 

3.弹簧弹簧

3.1 这个SpringBootServletInitializer运行一个来自传统战争部署的SpringApplication

SpringBootWebApplication.java

 package com.mkyong;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;@SpringBootApplication
public class SpringBootWebApplication extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(SpringBootWebApplication.class);}public static void main(String[] args) throws Exception {SpringApplication.run(SpringBootWebApplication.class, args);}} 

3.2 一个简单的 Spring 控制器类。

WelcomeController.java

 package com.mkyong;import java.util.Map;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class WelcomeController {// inject via application.properties@Value("${welcome.message:test}")private String message = "Hello World";@RequestMapping("/")public String welcome(Map<String, Object> model) {model.put("message", this.message);return "welcome";}} 

4.JSP +资源+静态文件

4.1 对于 JSP 文件,放入src/main/webapp/WEB-INF/jsp/

src/main/webapp/WEB-INF/jsp/welcome.jsp

 <!DOCTYPE html>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html lang="en">
<head><!-- Access the bootstrap Css like this, Spring boot will handle the resource mapping automcatically --><link rel="stylesheet" type="text/css" href="webjars/bootstrap/3.3.7/css/bootstrap.min.css" /><!-- <spring:url value="/css/main.css" var="springCss" /><link href="${springCss}" rel="stylesheet" />--><c:url value="/css/main.css" var="jstlCss" /><link href="${jstlCss}" rel="stylesheet" /></head>
<body><nav class="navbar navbar-inverse"><div class="container"><div class="navbar-header"><a class="navbar-brand" href="#">Spring Boot</a></div><div id="navbar" class="collapse navbar-collapse"><ul class="nav navbar-nav"><li class="active"><a href="#">Home</a></li><li><a href="#about">About</a></li></ul></div></div></nav><div class="container"><div class="starter-template"><h1>Spring Boot Web JSP Example</h1><h2>Message: ${message}</h2></div></div><script type="text/javascript" src="webjars/bootstrap/3.3.7/js/bootstrap.min.js"></script></body></html> 

4.2 对于 CSS 或 Javascript 等静态文件,放入/src/main/resources/static/

/src/main/resources/static/css/main.css

 h1{color:#0000FF;
}h2{color:#FF0000;
} 

4.3 对于属性文件,输入/src/main/resources/

/src/main/resources/application.properties

 spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jspwelcome.message: Hello Mkyong 

Note
Spring Boot, convention over configuration, no need to declare the resource mapping like this. The resource mapping just handles automatically – Read this article – Spring Boot Serving static content

5.演示

5.1 启动 Spring Boot 网络应用程序。

 project$ mvn spring-boot:run//....   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v1.4.2.RELEASE)2016-11-28 17:25:24.809  INFO 4696 --- [           main] com.mkyong.SpringBootWebApplication      : Starting SpringBootWebApplication on MKYONG-WIN10 with PID 4696 (C:\spring-boot\spring-boot-examples\spring-boot-web-jsp\target\classes started by mkyong in C:\spring-boot\spring-boot-examples\spring-boot-web-jsp)
2016-11-28 17:25:24.812  INFO 4696 --- [           main] com.mkyong.SpringBootWebApplication      : No active profile set, falling back to default profiles: default
2016-11-28 17:25:24.861  INFO 4696 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@69410cd3: startup date [Mon Nov 28 17:25:24 SGT 2016]; root of context hierarchy
2016-11-28 17:25:25.950  INFO 4696 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2016-11-28 17:25:25.965  INFO 4696 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2016-11-28 17:25:25.966  INFO 4696 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.6
2016-11-28 17:25:26.171  INFO 4696 --- [ost-startStop-1] org.apache.jasper.servlet.TldScanner     : At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
2016-11-28 17:25:26.180  INFO 4696 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2016-11-28 17:25:26.180  INFO 4696 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1322 ms
2016-11-28 17:25:26.304  INFO 4696 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2016-11-28 17:25:26.312  INFO 4696 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2016-11-28 17:25:26.313  INFO 4696 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2016-11-28 17:25:26.313  INFO 4696 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2016-11-28 17:25:26.314  INFO 4696 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]//...2016-11-28 17:25:26.841  INFO 4696 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2016-11-28 17:25:26.846  INFO 4696 --- [           main] com.mkyong.SpringBootWebApplication      : Started SpringBootWebApplication in 2.403 seconds (JVM running for 5.08) 

5.2 访问 http://localhost:8080

spring-boot-web-jsp-demo

5.3 Maven 将项目打包成可执行的WAR文件。在target文件夹中会生成一个 18M++的WAR文件。

 project$ mvn clean package...
[INFO] Building war: ...\spring-boot-web-jsp\target\spring-boot-web-jsp-1.0.war
[INFO]
[INFO] --- spring-boot-maven-plugin:1.4.2.RELEASE:repackage (default) @ spring-boot-web-jsp ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------ 

运行它,再次访问 http://localhost:8080

 project$ java -jar target/spring-boot-web-jsp-1.0.war 

JSP limitations
You can’t create an executable jar to run this embedded Tomcat + JSP web example, because of a hard coded file pattern in Tomcat. Read this Spring Boot – JSP limitation.

下载源代码

Download it – spring-boot-web-jsp.zip (8KB)

参考

  1. Spring Boot–静态内容
  2. SpringBootServletInitializer JavaDoc
  3. 部署 Spring Boot 应用
  4. Spring Boot–JSP 限制
  5. spring MVC–in ucci CSS 文件

Spring Boot Hello World 示例-小胡子

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-hello-world-example-mustache/

一个 Spring Boot 的 web 应用实例,使用embedded Tomcat + Mustache template engine,并打包成一个可执行的JAR文件。

使用的技术:

  1. Spring Boot 1.5.2 .版本
  2. 弹簧 4.3.7 .释放
  3. jmustache 1.13
  4. 百里香叶
  5. Tomcat Embed 8.5.11
  6. maven3
  7. Java 8

Note
Spring Boot uses jmustache to integrate Mustache as template engine.

1.项目目录

2.项目相关性

声明spring-boot-starter-mustache,它将获得开发Spring + Mustache web 应用程序所需的任何东西。

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>spring-boot-web-mustache</artifactId><packaging>jar</packaging><name>Spring Boot Web Mustache Example</name><description>Spring Boot Web Mustache Example</description><url>https://www.mkyong.com</url><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.2.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mustache</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- hot swapping, live reload --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><!-- Optional, for bootstrap --><dependency><groupId>org.webjars</groupId><artifactId>bootstrap</artifactId><version>3.3.7</version></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project> 

显示项目相关性:

 $ mvn dependency:tree[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Spring Boot Web Mustache Example 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.10:tree (default-cli) @ spring-boot-web-mustache ---[INFO] org.springframework.boot:spring-boot-web-mustache:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-mustache:jar:1.5.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:1.5.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:1.5.2.RELEASE:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.1.11:compile
[INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.1.11:compile
[INFO] |  |  |  +- org.slf4j:jcl-over-slf4j:jar:1.7.24:compile
[INFO] |  |  |  +- org.slf4j:jul-to-slf4j:jar:1.7.24:compile
[INFO] |  |  |  \- org.slf4j:log4j-over-slf4j:jar:1.7.24:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.17:runtime
[INFO] |  +- org.springframework.boot:spring-boot-starter-web:jar:1.5.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-tomcat:jar:1.5.2.RELEASE:compile
[INFO] |  |  |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.11:compile
[INFO] |  |  |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:8.5.11:compile
[INFO] |  |  |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.5.11:compile
[INFO] |  |  +- org.hibernate:hibernate-validator:jar:5.3.4.Final:compile
[INFO] |  |  |  +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO] |  |  |  +- org.jboss.logging:jboss-logging:jar:3.3.0.Final:compile
[INFO] |  |  |  \- com.fasterxml:classmate:jar:1.3.3:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.7:compile
[INFO] |  |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.0:compile
[INFO] |  |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.8.7:compile
[INFO] |  |  +- org.springframework:spring-web:jar:4.3.7.RELEASE:compile
[INFO] |  |  |  +- org.springframework:spring-aop:jar:4.3.7.RELEASE:compile
[INFO] |  |  |  \- org.springframework:spring-beans:jar:4.3.7.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-webmvc:jar:4.3.7.RELEASE:compile
[INFO] |  |     \- org.springframework:spring-expression:jar:4.3.7.RELEASE:compile
[INFO] |  \- com.samskivert:jmustache:jar:1.13:compile
[INFO] +- org.springframework.boot:spring-boot-starter-test:jar:1.5.2.RELEASE:test
[INFO] |  +- org.springframework.boot:spring-boot-test:jar:1.5.2.RELEASE:test
[INFO] |  +- org.springframework.boot:spring-boot-test-autoconfigure:jar:1.5.2.RELEASE:test
[INFO] |  +- com.jayway.jsonpath:json-path:jar:2.2.0:test
[INFO] |  |  +- net.minidev:json-smart:jar:2.2.1:test
[INFO] |  |  |  \- net.minidev:accessors-smart:jar:1.1:test
[INFO] |  |  |     \- org.ow2.asm:asm:jar:5.0.3:test
[INFO] |  |  \- org.slf4j:slf4j-api:jar:1.7.24:compile
[INFO] |  +- junit:junit:jar:4.12:test
[INFO] |  +- org.assertj:assertj-core:jar:2.6.0:test
[INFO] |  +- org.mockito:mockito-core:jar:1.10.19:test
[INFO] |  |  \- org.objenesis:objenesis:jar:2.1:test
[INFO] |  +- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] |  +- org.hamcrest:hamcrest-library:jar:1.3:test
[INFO] |  +- org.skyscreamer:jsonassert:jar:1.4.0:test
[INFO] |  |  \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test
[INFO] |  +- org.springframework:spring-core:jar:4.3.7.RELEASE:compile
[INFO] |  \- org.springframework:spring-test:jar:4.3.7.RELEASE:test
[INFO] +- org.springframework.boot:spring-boot-devtools:jar:1.5.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot:jar:1.5.2.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-context:jar:4.3.7.RELEASE:compile
[INFO] |  \- org.springframework.boot:spring-boot-autoconfigure:jar:1.5.2.RELEASE:compile
[INFO] \- org.webjars:bootstrap:jar:3.3.7:compile
[INFO]    \- org.webjars:jquery:jar:1.11.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.796 s
[INFO] Finished at: 2017-04-19T11:46:09+08:00
[INFO] Final Memory: 22M/437M
[INFO] ------------------------------------------------------------------------ 

3.Spring Boot

3.1 创建一个@SpringBootApplication类。运行这个类来启动 Spring Boot web 应用程序。

SpringBootWebApplication.java

 package com.mkyong;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBootWebApplication {public static void main(String[] args) throws Exception {SpringApplication.run(SpringBootWebApplication.class, args);}} 

3.2 一个简单的控制器类。

WelcomeController.java

 package com.mkyong;import java.util.Map;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class WelcomeController {// inject via application.properties@Value("${app.welcome.message}")private String MESSAGE = "";@Value("${app.welcome.title}")private String TITLE = "";@RequestMapping("/")public String welcome(Map<String, Object> model) {model.put("title", TITLE);model.put("message", MESSAGE);return "welcome";}// test 5xx errors@RequestMapping("/5xx")public String ServiceUnavailable() {throw new RuntimeException("ABC");}} 

4.小胡子+资源+静态文件

4.1 对于小胡子模板文件,放入src/main/resources/templates/

src/main/resources/templates/layout/header.html

 <!DOCTYPE HTML>
<head><title>{{title}}</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><link rel="stylesheet" type="text/css" href="webjars/bootstrap/3.3.7/css/bootstrap.min.css" />
<link rel="stylesheet" href="css/main.css" /></head>
<!--  this is header --> 

src/main/resources/templates/layout/footer.html

 <!--  this is footer -->
</html> 

src/main/resources/templates/welcome.html

 {{>layout/header}}
<body><nav class="navbar navbar-inverse"><div class="container"><div class="navbar-header"><a class="navbar-brand" href="#">Spring Boot</a></div></div></nav><div class="container"><div class="starter-template"><h1>Spring Boot Web Mustache Example</h1><h2>{{message}}</h2></div></div><!-- /.container --><script type="text/javascript" src="webjars/bootstrap/3.3.7/js/bootstrap.min.js"></script></body>
{{>layout/footer}} 

4.2 对于 CSS 或 Javascript 等静态文件,放入/src/main/resources/static/

/src/main/resources/static/css/main.css

 h1{color:#0000FF;
}h2{color:#FF0000;
} 

4.3 对于错误模板。

Note
Read this Spring Boot – Error Handling to understand how the default error mapping page works.src/main/resources/templates/error.html

 <!DOCTYPE html><html lang="en"><body>Something went wrong: {{status}} {{error}}
</body></html> 

src/main/resources/templates/error/5xx.html

 <!DOCTYPE html><html lang="en"><body>I'm a 5xx
</body></html> 

4.4 对于属性文件,输入/src/main/resources/

/src/main/resources/application.properties

 app.welcome.message: Hello Mkyong
app.welcome.title: Spring Boot Mustache Hello World Example 

Note
Read this Spring Boot Serving static content to understand the resource mapping.

5.单元测试

5.1 单元测试示例测试上面的 Spring Boot web 应用程序。

MustacheApplicationTests

 package com.mkyong;import static org.assertj.core.api.Assertions.assertThat;import java.util.Arrays;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext
public class MustacheApplicationTests {@Autowiredprivate TestRestTemplate restTemplate;@Testpublic void testMainPage() throws Exception {ResponseEntity<String> entity = this.restTemplate.getForEntity("/", String.class);assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);assertThat(entity.getBody()).contains("Hello Mkyong");}@Testpublic void test404Page() throws Exception {HttpHeaders headers = new HttpHeaders();headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));HttpEntity<String> requestEntity = new HttpEntity<String>(headers);ResponseEntity<String> responseEntity = this.restTemplate.exchange("/uri-not-exist", HttpMethod.GET,requestEntity, String.class);assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);assertThat(responseEntity.getBody()).contains("Something went wrong: 404 Not Found");}@Testpublic void test5xxPage() throws Exception {HttpHeaders headers = new HttpHeaders();headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));HttpEntity<String> requestEntity = new HttpEntity<String>(headers);ResponseEntity<String> responseEntity = this.restTemplate.exchange("/5xx", HttpMethod.GET, requestEntity,String.class);assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);assertThat(responseEntity.getBody()).contains("I'm a 5xx");}} 

6.演示

Note
In IDE, run the @SpringBootApplication annotated class, and the entire Spring Boot application will be started.

6.1 启动 Spring Boot 网络应用程序。

Terminal

 project$ mvn spring-boot:run//....   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v1.5.2.RELEASE)2017-04-19 12:17:38.014  INFO 6232 --- [  restartedMain] com.mkyong.SpringBootWebApplication      : Starting SpringBootWebApplication on MKYONG-WIN10 with PID 6232 (C:\spring-boot\spring-boot-examples\spring-boot-web-mustache\target\classes started by mkyong in C:\spring-boot\spring-boot-examples\spring-boot-web-mustache)
2017-04-19 12:17:38.015  INFO 6232 --- [  restartedMain] com.mkyong.SpringBootWebApplication      : No active profile set, falling back to default profiles: default
2017-04-19 12:17:38.074  INFO 6232 --- [  restartedMain] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@af1619: startup date [Wed Apr 19 12:17:38 SGT 2017]; root of context hierarchy
2017-04-19 12:17:39.352  INFO 6232 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-04-19 12:17:39.370  INFO 6232 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service Tomcat
2017-04-19 12:17:39.372  INFO 6232 --- [  restartedMain] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.11
2017-04-19 12:17:39.481  INFO 6232 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2017-04-19 12:17:39.481  INFO 6232 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1410 ms
2017-04-19 12:17:39.649  INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2017-04-19 12:17:39.658  INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-04-19 12:17:39.659  INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-04-19 12:17:39.659  INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-04-19 12:17:39.660  INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2017-04-19 12:17:39.938  INFO 6232 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@af1619: startup date [Wed Apr 19 12:17:38 SGT 2017]; root of context hierarchy
2017-04-19 12:17:39.997  INFO 6232 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String com.mkyong.WelcomeController.welcome(java.util.Map<java.lang.String, java.lang.Object>)
2017-04-19 12:17:39.997  INFO 6232 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/5xx]}" onto public java.lang.String com.mkyong.WelcomeController.ServiceUnavailable()
2017-04-19 12:17:40.006  INFO 6232 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-04-19 12:17:40.006  INFO 6232 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-04-19 12:17:40.041  INFO 6232 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-04-19 12:17:40.041  INFO 6232 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-04-19 12:17:40.090  INFO 6232 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-04-19 12:17:40.332  INFO 6232 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2017-04-19 12:17:40.373  INFO 6232 --- [  restartedMain] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2017-04-19 12:17:40.427  INFO 6232 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-04-19 12:17:40.435  INFO 6232 --- [  restartedMain] com.mkyong.SpringBootWebApplication      : Started SpringBootWebApplication in 2.737 seconds (JVM running for 3.124) 

6.2 访问 http://localhost:8080

6.2 访问http://localhost:8080/uri-not-exist

6.2 访问http://localhost:8080/5xx

6.构建可执行的 JAR

6.1 将项目打包,创建一个可执行的JAR文件。

 project$ mvn clean package 

6.2 运行它,再次访问 http://localhost:8080

 project$ java -jar target/spring-boot-web-mustache-1.0.jar 

下载源代码

Download it – spring-boot-web-mustache.zip (11 KB)

参考

  1. 小胡子模板引擎
  2. jmustache——Mustache 模板语言的 Java 实现
  3. Spring Boot–错误处理
  4. Spring Boot–静态内容
  5. 部署 Spring Boot 应用
  6. spring MVC–in ucci CSS 文件
  7. Spring Boot——开发者工具
  8. 使用 Spring MVC 提供 Web 内容
  9. Spring Boot Hello World 示例–JSP

Spring Boot Hello World 示例-百里香叶

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-hello-world-example-thymeleaf/

在本文中,我们将向您展示如何开发一个 Spring Boot web 应用程序,使用百里香叶视图,嵌入式 Tomcat,并将其打包为一个可执行的JAR文件。

使用的技术:

  • Spring Boot 2.1.2 .版本
  • 弹簧 5.1.4 释放
  • 百里香叶
  • Tomcat embed 9.0.14
  • JUnit 4.12
  • maven3
  • Java 8

1.项目目录

project directory

2.专家

放上spring-boot-starter-webspring-boot-starter-thymeleaf,它将获得我们开发 Spring MVC + Thymeleaf web 应用程序所需的任何东西,包括嵌入式 Tomcat 服务器。

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>web-thymeleaf</artifactId><packaging>jar</packaging><name>Spring Boot Web Thymeleaf Example</name><description>Spring Boot Web Thymeleaf Example</description><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version></parent><properties><java.version>1.8</java.version><bootstrap.version>4.2.1</bootstrap.version></properties><dependencies><!-- web mvc --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- thymeleaf --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- test --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- hot swapping, disable cache for template, enable live reload --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><!-- Optional, for bootstrap --><dependency><groupId>org.webjars</groupId><artifactId>bootstrap</artifactId><version>${bootstrap.version}</version></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><addResources>true</addResources></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.22.0</version></plugin></plugins></build>
</project> 

显示项目依赖关系。

 $ mvn dependency:tree[INFO] org.springframework.boot:web-thymeleaf:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.1.2.RELEASE:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] |  |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.11.1:compile
[INFO] |  |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.11.1:compile
[INFO] |  |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
[INFO] |  |  +- javax.annotation:javax.annotation-api:jar:1.3.2:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.23:runtime
[INFO] |  +- org.springframework.boot:spring-boot-starter-json:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.8:compile
[INFO] |  |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile
[INFO] |  |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.9.8:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.9.8:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.9.8:compile
[INFO] |  |  \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.9.8:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.14:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:9.0.14:compile
[INFO] |  |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.14:compile
[INFO] |  +- org.hibernate.validator:hibernate-validator:jar:6.0.14.Final:compile
[INFO] |  |  +- javax.validation:validation-api:jar:2.0.1.Final:compile
[INFO] |  |  +- org.jboss.logging:jboss-logging:jar:3.3.2.Final:compile
[INFO] |  |  \- com.fasterxml:classmate:jar:1.4.0:compile
[INFO] |  +- org.springframework:spring-web:jar:5.1.4.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-beans:jar:5.1.4.RELEASE:compile
[INFO] |  \- org.springframework:spring-webmvc:jar:5.1.4.RELEASE:compile
[INFO] |     +- org.springframework:spring-aop:jar:5.1.4.RELEASE:compile
[INFO] |     +- org.springframework:spring-context:jar:5.1.4.RELEASE:compile
[INFO] |     \- org.springframework:spring-expression:jar:5.1.4.RELEASE:compile
[INFO] +- org.springframework.boot:spring-boot-starter-thymeleaf:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.thymeleaf:thymeleaf-spring5:jar:3.0.11.RELEASE:compile
[INFO] |  |  +- org.thymeleaf:thymeleaf:jar:3.0.11.RELEASE:compile
[INFO] |  |  |  +- org.attoparser:attoparser:jar:2.0.5.RELEASE:compile
[INFO] |  |  |  \- org.unbescape:unbescape:jar:1.1.6.RELEASE:compile
[INFO] |  |  \- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] |  \- org.thymeleaf.extras:thymeleaf-extras-java8time:jar:3.0.2.RELEASE:compile
[INFO] +- org.springframework.boot:spring-boot-starter-test:jar:2.1.2.RELEASE:test
[INFO] |  +- org.springframework.boot:spring-boot-test:jar:2.1.2.RELEASE:test
[INFO] |  +- org.springframework.boot:spring-boot-test-autoconfigure:jar:2.1.2.RELEASE:test
[INFO] |  +- com.jayway.jsonpath:json-path:jar:2.4.0:test
[INFO] |  |  \- net.minidev:json-smart:jar:2.3:test
[INFO] |  |     \- net.minidev:accessors-smart:jar:1.2:test
[INFO] |  |        \- org.ow2.asm:asm:jar:5.0.4:test
[INFO] |  +- junit:junit:jar:4.12:test
[INFO] |  +- org.assertj:assertj-core:jar:3.11.1:test
[INFO] |  +- org.mockito:mockito-core:jar:2.23.4:test
[INFO] |  |  +- net.bytebuddy:byte-buddy:jar:1.9.7:test
[INFO] |  |  +- net.bytebuddy:byte-buddy-agent:jar:1.9.7:test
[INFO] |  |  \- org.objenesis:objenesis:jar:2.6:test
[INFO] |  +- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] |  +- org.hamcrest:hamcrest-library:jar:1.3:test
[INFO] |  +- org.skyscreamer:jsonassert:jar:1.5.0:test
[INFO] |  |  \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test
[INFO] |  +- org.springframework:spring-core:jar:5.1.4.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-jcl:jar:5.1.4.RELEASE:compile
[INFO] |  +- org.springframework:spring-test:jar:5.1.4.RELEASE:test
[INFO] |  \- org.xmlunit:xmlunit-core:jar:2.6.2:test
[INFO] |     \- javax.xml.bind:jaxb-api:jar:2.3.1:test
[INFO] |        \- javax.activation:javax.activation-api:jar:1.2.0:test
[INFO] +- org.springframework.boot:spring-boot-devtools:jar:2.1.2.RELEASE:compile (optional)
[INFO] |  +- org.springframework.boot:spring-boot:jar:2.1.2.RELEASE:compile
[INFO] |  \- org.springframework.boot:spring-boot-autoconfigure:jar:2.1.2.RELEASE:compile
[INFO] \- org.webjars:bootstrap:jar:4.2.1:compile
[INFO]    +- org.webjars:jquery:jar:3.0.0:compile
[INFO]    \- org.webjars:popper.js:jar:1.14.3:compile 

3.开发者工具

 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency> 

这个spring-boot-devtools有助于禁用高速缓存并启用热插拔,这样开发人员将总是看到最后的更改。有利于发展。阅读此–Spring Boot–开发者工具尝试修改百里香模板或属性文件,刷新浏览器以查看更改是否立即生效。

  • 对于 Eclipse IDE 来说,它与spring-boot-devtools集成得很好。
  • 对于 Intellij IDEA,需要额外的步骤,阅读此重新加载静态文件不工作

4.Spring Boot + MVC

4.1 简单的控制器。

WelcomeController.java

 package com.mkyong.controller;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;import java.util.Arrays;
import java.util.List;@Controller
public class WelcomeController {// inject via application.properties@Value("${welcome.message}")private String message;private List<String> tasks = Arrays.asList("a", "b", "c", "d", "e", "f", "g");@GetMapping("/")public String main(Model model) {model.addAttribute("message", message);model.addAttribute("tasks", tasks);return "welcome"; //view}// /hello?name=kotlin@GetMapping("/hello")public String mainWithParam(@RequestParam(name = "name", required = false, defaultValue = "") String name, Model model) {model.addAttribute("message", name);return "welcome"; //view}} 

4.2 创建一个类并用@SpringBootApplication标注。在 IDE 中,运行此类来启动整个 web 应用程序。

StartWebApplication.java

 package com.mkyong;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class StartWebApplication {public static void main(String[] args) {SpringApplication.run(StartWebApplication.class, args);}} 

5.百里香+静态文件

Note
Read this Spring Boot Serving static content to understand the resource mapping.

5.1 对于百里香模板文件,放入src/main/resources/templates/

src/main/resources/templates/welcome.html

 <!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><title>Spring Boot Thymeleaf Hello World Example</title><link rel="stylesheet" th:href="@{webjars/bootstrap/4.2.1/css/bootstrap.min.css}"/><link rel="stylesheet" th:href="@{/css/main.css}"/></head><body><nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top"><a class="navbar-brand" href="#">Mkyong.com</a>
</nav><main role="main" class="container"><div class="starter-template"><h1>Spring Boot Web Thymeleaf Example</h1><h2><span th:text="'Hello, ' + ${message}"></span></h2></div><ol><li th:each="task : ${tasks}" th:text="${task}"></li></ol></main>
<!-- /.container --><script type="text/javascript" th:src="@{webjars/bootstrap/4.2.1/js/bootstrap.min.js}"></script>
</body>
</html> 

5.2 Spring Boot 通用应用属性

src/main/resources/application.properties

 welcome.message: Mkyongspring.thymeleaf.cache=false 

5.3 对于 CSS 或 JS 等静态文件,放入src/main/resources/static/

src/main/resources/static/css/main.css

 body {padding-top: 5rem;
}
.starter-template {padding: 3rem 1.5rem;text-align: center;
}h1{color:#0000FF;
}h2{color:#FF0000;
} 

6.单元测试

MockMvc测试 Spring MVC 控制器。

WelcomeControllerTest.java

 package com.mkyong;import com.mkyong.controller.WelcomeController;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.web.servlet.ModelAndView;import java.util.Arrays;
import java.util.List;import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@RunWith(SpringRunner.class)
@WebMvcTest(controllers = WelcomeController.class)
public class WelcomeControllerTest {@Autowiredprivate MockMvc mockMvc;List<String> expectedList = Arrays.asList("a", "b", "c", "d", "e", "f", "g");@Testpublic void main() throws Exception {ResultActions resultActions = mockMvc.perform(get("/")).andExpect(status().isOk()).andExpect(view().name("welcome")).andExpect(model().attribute("message", equalTo("Mkyong"))).andExpect(model().attribute("tasks", is(expectedList))).andExpect(content().string(containsString("Hello, Mkyong")));MvcResult mvcResult = resultActions.andReturn();ModelAndView mv = mvcResult.getModelAndView();//}// Get request with Param@Testpublic void hello() throws Exception {mockMvc.perform(get("/hello").param("name", "I Love Kotlin!")).andExpect(status().isOk()).andExpect(view().name("welcome")).andExpect(model().attribute("message", equalTo("I Love Kotlin!"))).andExpect(content().string(containsString("Hello, I Love Kotlin!")));}} 

7.演示

 $ mvn spring-boot:run: Tomcat initialized with port(s): 8080 (http)
: Starting service [Tomcat]
: Starting Servlet engine: [Apache Tomcat/9.0.14]: Tomcat started on port(s): 8080 (http) with context path ''Started StartWebApplication in 1.858 seconds (JVM running for 2.222) 

URL = http://localhost:8080

URL =http://localhost:8080/hello?name=abc

8.创建可执行的 JAR

对于部署,只需普通的 Maven 包来创建一个可执行的 JAR 文件。

 $ mvn clean package$ java -jar target\web-thymeleaf-1.0.jar 

下载源代码

$ git clone https://github.com/mkyong/spring-boot.git
$ cd web-thymeleaf
$ mvn spring-boot:run

参考

  • 使用 Spring MVC 提供 Web 内容
  • JUnit–如何测试列表
  • Spring Boot +朱尼特 5 +莫奇托
  • 常用应用属性
  • Intellij IDEA–Spring boot 重新加载静态文件不起作用
  • 百里香官网
  • Spring Boot–静态内容
  • Spring Boot——开发者工具
  • 部署 Spring Boot 应用
  • spring MVC–in ucci CSS 文件
  • Spring Boot Hello World 示例–JSP

Spring Boot——如何改变语境路径

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-how-to-change-context-path/

在 Spring Boot,要改变上下文路径,更新server.contextPath属性。以下示例将上下文路径从/更新为/mkyonghttp://localhost:8080/mkyong

Note
By default, the context path is “/”.

PS 用 Spring Boot 1.4.2.RELEASE 测试

1.属性和 Yaml

1.1 通过属性文件更新。

/src/main/resources/application.properties

 server.port=8080
server.contextPath=/mkyong 

1.2 通过 yaml 文件更新。

/src/main/resources/application.yml

 server:port: 8080contextPath: /mkyong 

2.嵌入式 ServletContainerCustomizer

通过代码更新,这将覆盖属性和 yaml 设置。

CustomContainer.java

 package com.mkyong;import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.stereotype.Component;@Component
public class CustomContainer implements EmbeddedServletContainerCustomizer {@Overridepublic void customize(ConfigurableEmbeddedServletContainer container) {container.setPort(8080);container.setContextPath("/mkyong");}} 

3.命令行

通过直接传递系统属性来更新上下文路径。

Terminal

 java -jar -Dserver.contextPath=/mkyong spring-boot-example-1.0.jar 

参考

  1. Spring Boot——嵌入式 servlet 容器
  2. Spring Boot–外部化配置
  3. Spring Boot——如何更改 Tomcat 端口

Spring Boot——如何更改 Tomcat 端口

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-how-to-change-tomcat-port/

在 Spring Boot,要改变嵌入式 Tomcat 的初始化端口(8080),更新server.port属性。

PS 用 Spring Boot 1.4.2.RELEASE 测试

1.属性和 Yaml

1.1 通过属性文件更新。

/src/main/resources/application.properties

 server.port=8888 

1.2 通过 yaml 文件更新。

/src/main/resources/application.yml

 server:port: 8888 

2.嵌入式 ServletContainerCustomizer

通过代码更新,这将覆盖属性和 yaml 设置。

CustomContainer.java

 package com.mkyong;import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.stereotype.Component;@Component
public class CustomContainer implements EmbeddedServletContainerCustomizer {@Overridepublic void customize(ConfigurableEmbeddedServletContainer container) {container.setPort(8888);}} 

3.命令行

通过直接传递系统属性来更新端口。

Terminal

 java -jar -Dserver.port=8888 spring-boot-example-1.0.jar 

参考

  1. Spring Boot——嵌入式 servlet 容器
  2. Spring Boot–外部化配置
  3. Spring Boot——如何改变上下文路径

Spring Boot——如何禁用 Spring 徽标横幅

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-how-to-disable-the-spring-logo-banner/

以下是禁用 Spring 徽标横幅的几种方法:

 .   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v1.5.1.RELEASE) 

Note
You may interest in this – Spring Boot – Custom Banner example

解决办法

1.SpringApplication主要方法。

SpringBootConsoleApplication.java

 package com.mkyong;import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBootConsoleApplication {public static void main(String[] args) throws Exception {SpringApplication app = new SpringApplication(SpringBootConsoleApplication.class);app.setBannerMode(Banner.Mode.OFF);app.run(args);}} 

Note
There are 3 Banner.Mode

  1. 关–禁止打印横幅。
  2. 控制台–将横幅打印到 System.out。
  3. 日志–将横幅打印到日志文件中。

2.应用程序属性文件。

application.properties

 spring.main.banner-mode=off 

3.应用程序 YAML 文件。

application.yml

 spring:main:banner-mode:"off" 

4.作为系统属性传递

Terminal

 $ java -Dspring.main.banner-mode=off -jar spring-boot-simple-1.0.jar 

参考

  1. Spring Boot–定制横幅示例
  2. Spring Boot 横幅

banner spring boot (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190214233233/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')

Spring Boot——如何初始化用于测试的 Bean?

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-how-to-init-a-bean-for-testing/

在 Spring Boot,我们可以创建一个@TestConfiguration类来初始化一些只用于测试类的 beans。

用 Spring Boot 2 号进行了测试

1.@测试配置+@导入

这个@TestConfiguration类不会被组件扫描选中,我们需要手动导入它。

TestConfig.java

 package com.mkyong;import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;import java.time.Duration;@TestConfiguration
public class TestConfig {@Beanpublic RestTemplateBuilder restTemplateBuilder() {return new RestTemplateBuilder().basicAuthentication("mkyong", "password").setConnectTimeout(Duration.ofSeconds(5));}
} 

RestTemplateTest.java

 package com.mkyong;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)
@SpringBootTest
@Import(TestConfig.class)
public class RestTemplateTest {@Autowiredprivate TestRestTemplate restTemplate;@Testpublic void post_user_ok() {//...}} 

2.@TestConfiguration +内部静态类

或者,创建一个内部类,如下所示:

RestTemplateTest.java

 package com.mkyong;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit4.SpringRunner;import java.time.Duration;@RunWith(SpringRunner.class)
@SpringBootTest
public class RestTemplateTest {@TestConfigurationstatic class TestConfig {@Beanpublic RestTemplateBuilder restTemplateBuilder() {return new RestTemplateBuilder().basicAuthentication("mkyong", "password").setConnectTimeout(Duration.ofSeconds(5));}}@Autowiredprivate TestRestTemplate restTemplate;@Testpublic void post_user_ok() {//...}} 

参考

  • 测试 Spring Boot 应用

Spring Boot——如何知道使用了哪个连接池?

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-how-to-know-which-connection-pool-is-used/

在 Spring Boot,@Autowired a javax.sql.DataSource,你就会知道当前运行的应用程序使用的是哪个数据库连接池。

1.测试默认值

Spring Boot 举例打印一份javax.sql.DataSource

Note
Read this official Spring Boot doc – Connection to a production database, to understand the algorithm for choosing a DataSource implementations – Tomcat pooling, HikariCP, Commons DBCP and Commons DBCP2.

 package com.mkyong;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;import javax.sql.DataSource;@SpringBootApplication
public class SpringBootConsoleApplication implements CommandLineRunner {@AutowiredDataSource dataSource;public static void main(String[] args) throws Exception {SpringApplication.run(SpringBootConsoleApplication.class, args);}@Overridepublic void run(String... args) throws Exception {System.out.println("DATASOURCE = " + dataSource);}} 

输出,Spring Boot 默认使用 Tomcat 池。

 DATASOURCE = org.apache.tomcat.jdbc.pool.DataSource@7c541c15... 

2.hikaricp 测试

要切换到另一个连接池,例如 HikariCP,只需排除默认连接池,并将 HikariCP 包含在类路径中。

pom.xml

 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId><exclusions><exclusion><groupId>org.apache.tomcat</groupId><artifactId>tomcat-jdbc</artifactId></exclusion></exclusions></dependency><!-- connection pools --><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>2.6.0</version></dependency> 

输出

 DATASOURCE = HikariDataSource (HikariPool-1) 

Note
Read this example – Spring Boot JDBC + MySQL + HikariCP example ## 参考

  1. 鼠标指针
  2. Spring Boot JDBC+MySQL+HikariCP 的例子

connection pool hikaricp spring boot tomcat pool

Spring Boot——如何通过 SMTP 发送电子邮件

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-how-to-send-email-via-smtp/

spring boot sending email

在本教程中,我们将向您展示如何在 Spring Boot 通过 SMTP 发送电子邮件。

使用的技术:

  • Spring Boot 2.1.2 .版本
  • 弹簧 5.1.4 释放
  • Java 邮件 1.6.2
  • maven3
  • Java 8

1.项目目录

project directory

2.专家

spring-boot-starter-mail声明,为了发送电子邮件,它将提取 JavaMail 依赖项。

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>spring-boot-send-email</artifactId><packaging>jar</packaging><name>Spring Boot Send Email</name><url>https://www.mkyong.com</url><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- send email --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.22.0</version></plugin></plugins></build>
</project> 

显示项目依赖关系。

 $ mvn dependency:tree[INFO] org.springframework.boot:spring-boot-send-email:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot:jar:2.1.2.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-context:jar:5.1.4.RELEASE:compile
[INFO] |  |     +- org.springframework:spring-aop:jar:5.1.4.RELEASE:compile
[INFO] |  |     \- org.springframework:spring-expression:jar:5.1.4.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] |  |  |  +- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] |  |  |  \- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.11.1:compile
[INFO] |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.11.1:compile
[INFO] |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
[INFO] |  +- javax.annotation:javax.annotation-api:jar:1.3.2:compile
[INFO] |  +- org.springframework:spring-core:jar:5.1.4.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-jcl:jar:5.1.4.RELEASE:compile
[INFO] |  \- org.yaml:snakeyaml:jar:1.23:runtime[INFO] \- org.springframework.boot:spring-boot-starter-mail:jar:2.1.2.RELEASE:compile
[INFO]    +- org.springframework:spring-context-support:jar:5.1.4.RELEASE:compile
[INFO]    |  \- org.springframework:spring-beans:jar:5.1.4.RELEASE:compile
[INFO]    \- com.sun.mail:javax.mail:jar:1.6.2:compile
[INFO]       \- javax.activation:activation:jar:1.1:compile 

3.Gmail SMTP

本例使用 Gmail SMTP 服务器,通过 TLS(端口 587)和 SSL(端口 465)进行测试。阅读此 Gmail SMTP

application.properties

 spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=username
spring.mail.password=password# Other properties
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000# TLS , port 587
spring.mail.properties.mail.smtp.starttls.enable=true# SSL, post 465
#spring.mail.properties.mail.smtp.socketFactory.port = 465
#spring.mail.properties.mail.smtp.socketFactory.class = javax.net.ssl.SSLSocketFactory 

Note
For Gmail SMTP, if your account is enabled the 2-Step verification, please create an “App Password”. Read more on this JavaMail – Sending email via Gmail SMTP example

4.发送电子邮件

Spring 在JavaMailAPI 之上提供了一个JavaMailSender接口。

4.1 发送普通文本邮件。

 import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;@Autowiredprivate JavaMailSender javaMailSender;void sendEmail() {SimpleMailMessage msg = new SimpleMailMessage();msg.setTo("to_1@gmail.com", "to_2@gmail.com", "to_3@yahoo.com");msg.setSubject("Testing from Spring Boot");msg.setText("Hello World \n Spring Boot Email");javaMailSender.send(msg);} 

4.2 发送一封 HTML 邮件和一个文件附件。

 import org.springframework.core.io.ClassPathResource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;void sendEmailWithAttachment() throws MessagingException, IOException {MimeMessage msg = javaMailSender.createMimeMessage();// true = multipart messageMimeMessageHelper helper = new MimeMessageHelper(msg, true);helper.setTo("to_@email");helper.setSubject("Testing from Spring Boot");// default = text/plain//helper.setText("Check attachment for image!");// true = text/htmlhelper.setText("<h1>Check attachment for image!</h1>", true);// hard coded a file path//FileSystemResource file = new FileSystemResource(new File("path/android.png"));helper.addAttachment("my_photo.png", new ClassPathResource("android.png"));javaMailSender.send(msg);} 

5.演示

5.1 启动 Spring Boot,它会发出一封邮件。

Application.java

 package com.mkyong;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.IOException;@SpringBootApplication
public class Application implements CommandLineRunner {@Autowiredprivate JavaMailSender javaMailSender;public static void main(String[] args) {SpringApplication.run(Application.class, args);}@Overridepublic void run(String... args) {System.out.println("Sending Email...");try {sendEmail();//sendEmailWithAttachment();} catch (MessagingException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}System.out.println("Done");}void sendEmail() {SimpleMailMessage msg = new SimpleMailMessage();msg.setTo("1@gmail.com", "2@yahoo.com");msg.setSubject("Testing from Spring Boot");msg.setText("Hello World \n Spring Boot Email");javaMailSender.send(msg);}void sendEmailWithAttachment() throws MessagingException, IOException {MimeMessage msg = javaMailSender.createMimeMessage();// true = multipart messageMimeMessageHelper helper = new MimeMessageHelper(msg, true);helper.setTo("1@gmail.com");helper.setSubject("Testing from Spring Boot");// default = text/plain//helper.setText("Check attachment for image!");// true = text/htmlhelper.setText("<h1>Check attachment for image!</h1>", true);helper.addAttachment("my_photo.png", new ClassPathResource("android.png"));javaMailSender.send(msg);}
} 

Terminal

 .   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v2.1.2.RELEASE)Sending Email...
Done 

下载源代码

$ git clone https://github.com/mkyong/spring-boot.git
$ cd email

//更新 application.properties 中的 SMTP 信息

$ mvn 弹簧启动:运行

参考

  • 春季邮件
  • Spring Boot 发送邮件
  • Java 邮件
  • JavaMail–通过 Gmail SMTP 发送电子邮件示例

Spring Boot JDBC 的例子

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-jdbc-examples/

spring boot spring jdbc

在本教程中,我们将向您展示如何使用 Spring Boot JDBC JdbcTemplateNamedParameterJdbcTemplate

使用的技术:

  • Spring Boot 2.1.2 .版本
  • 春季 JDBC 5.1.4 .发布
  • HikariCP 3.2.0
  • H2 内存数据库 1.4.197
  • maven3
  • Java 8

在 Spring Boot JDBC,数据库相关的 bean 如DataSourceJdbcTemplateNamedParameterJdbcTemplate将在启动时配置和创建,要使用它,只需@Autowired你想要的 bean,例如:

 @AutowiredJdbcTemplate jdbcTemplate;@Autowiredprivate NamedParameterJdbcTemplate jdbcTemplate; 

要连接到数据库(例如 MySQL),请在项目类路径中包含 JDBC 驱动程序:

pom.xml

 <!-- MySQL JDBC driver --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency> 

并在application.properties中定义datasoure属性

application.properties

 ## MySQL
#spring.datasource.url=jdbc:mysql://192.168.1.4:3306/test
#spring.datasource.username=mkyong
#spring.datasource.password=password# Oracle
#spring.datasource.url=jdbc:oracle:thin:@localhost:1521:orcl
#spring.datasource.username=system
#spring.datasource.password=Password123 

Note
By default, Spring Boot 2 uses HikariCP as the database connection pool.

1.项目目录

project directory

2.专家

2.1 spring-boot-starter-jdbc就是我们需要的。

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>spring-jdbc</artifactId><packaging>jar</packaging><name>Spring Boot JDBC</name><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version></parent><properties><java.version>1.8</java.version><downloadSources>true</downloadSources><downloadJavadocs>true</downloadJavadocs></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><!-- MySQL JDBC driver<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency>--><!-- in-memory database --><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.22.0</version></plugin></plugins></build>
</project> 

显示项目依赖关系。

 $ mvn dependency:tree[INFO] org.springframework.boot:spring-jdbc:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-jdbc:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot:jar:2.1.2.RELEASE:compile
[INFO] |  |  |  \- org.springframework:spring-context:jar:5.1.4.RELEASE:compile
[INFO] |  |  |     +- org.springframework:spring-aop:jar:5.1.4.RELEASE:compile
[INFO] |  |  |     \- org.springframework:spring-expression:jar:5.1.4.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.1.2.RELEASE:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] |  |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.11.1:compile
[INFO] |  |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.11.1:compile
[INFO] |  |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
[INFO] |  |  +- javax.annotation:javax.annotation-api:jar:1.3.2:compile
[INFO] |  |  +- org.springframework:spring-core:jar:5.1.4.RELEASE:compile
[INFO] |  |  |  \- org.springframework:spring-jcl:jar:5.1.4.RELEASE:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.23:runtime
[INFO] |  +- com.zaxxer:HikariCP:jar:3.2.0:compile
[INFO] |  |  \- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] |  \- org.springframework:spring-jdbc:jar:5.1.4.RELEASE:compile
[INFO] |     +- org.springframework:spring-beans:jar:5.1.4.RELEASE:compile
[INFO] |     \- org.springframework:spring-tx:jar:5.1.4.RELEASE:compile
[INFO] +- com.h2database:h2:jar:1.4.197:compile 

3.图书仓库

存储库的纯 Java 接口,稍后用JdbcTemplateNamedParameterJdbcTemplate实现

BookRepository.java

 package com.mkyong.repository;import com.mkyong.Book;import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;public interface BookRepository {int count();int save(Book book);int update(Book book);int deleteById(Long id);List<Book> findAll();List<Book> findByNameAndPrice(String name, BigDecimal price);Optional<Book> findById(Long id);String getNameById(Long id);} 

Book.java

 package com.mkyong;import java.math.BigDecimal;public class Book {private Long id;private String name;private BigDecimal price;//... setters getters constructors...
} 

4.JDBC 模板

4.1 一些积垢示例:

JdbcBookRepository.java

 package com.mkyong.repository;import com.mkyong.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;@Repository
public class JdbcBookRepository implements BookRepository {// Spring Boot will create and configure DataSource and JdbcTemplate// To use it, just @Autowired@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic int count() {return jdbcTemplate.queryForObject("select count(*) from books", Integer.class);}@Overridepublic int save(Book book) {return jdbcTemplate.update("insert into books (name, price) values(?,?)",book.getName(), book.getPrice());}@Overridepublic int update(Book book) {return jdbcTemplate.update("update books set price = ? where id = ?",book.getPrice(), book.getId());}@Overridepublic int deleteById(Long id) {return jdbcTemplate.update("delete books where id = ?",id);}@Overridepublic List<Book> findAll() {return jdbcTemplate.query("select * from books",(rs, rowNum) ->new Book(rs.getLong("id"),rs.getString("name"),rs.getBigDecimal("price")));}// jdbcTemplate.queryForObject, populates a single object@Overridepublic Optional<Book> findById(Long id) {return jdbcTemplate.queryForObject("select * from books where id = ?",new Object[]{id},(rs, rowNum) ->Optional.of(new Book(rs.getLong("id"),rs.getString("name"),rs.getBigDecimal("price"))));}@Overridepublic List<Book> findByNameAndPrice(String name, BigDecimal price) {return jdbcTemplate.query("select * from books where name like ? and price <= ?",new Object[]{"%" + name + "%", price},(rs, rowNum) ->new Book(rs.getLong("id"),rs.getString("name"),rs.getBigDecimal("price")));}@Overridepublic String getNameById(Long id) {return jdbcTemplate.queryForObject("select name from books where id = ?",new Object[]{id},String.class);}} 

5.NamedParameterJdbcTemplate

5.1NamedParameterJdbcTemplate在经典占位符?参数的 steads 中增加了对命名参数的支持。

NamedParameterJdbcBookRepository.java

 package com.mkyong.repository;import com.mkyong.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;@Repository
public class NamedParameterJdbcBookRepository extends JdbcBookRepository {@Autowiredprivate NamedParameterJdbcTemplate namedParameterJdbcTemplate;@Overridepublic int update(Book book) {return namedParameterJdbcTemplate.update("update books set price = :price where id = :id",new BeanPropertySqlParameterSource(book));}@Overridepublic Optional<Book> findById(Long id) {return namedParameterJdbcTemplate.queryForObject("select * from books where id = :id",new MapSqlParameterSource("id", id),(rs, rowNum) ->Optional.of(new Book(rs.getLong("id"),rs.getString("name"),rs.getBigDecimal("price"))));}@Overridepublic List<Book> findByNameAndPrice(String name, BigDecimal price) {MapSqlParameterSource mapSqlParameterSource = new MapSqlParameterSource();mapSqlParameterSource.addValue("name", "%" + name + "%");mapSqlParameterSource.addValue("price", price);return namedParameterJdbcTemplate.query("select * from books where name like :name and price <= :price",mapSqlParameterSource,(rs, rowNum) ->new Book(rs.getLong("id"),rs.getString("name"),rs.getBigDecimal("price")));}} 

6.应用程序.属性

6.1 对于内存数据库,没有什么需要配置的,如果我们想连接一个真实的数据库,定义一个datasource.url属性:

application.properties

 logging.level.org.springframework=info
#logging.level.org.springframework.jdbc=DEBUG
logging.level.com.mkyong=INFO
logging.level.com.zaxxer=DEBUG
logging.level.root=ERRORspring.datasource.hikari.connectionTimeout=20000
spring.datasource.hikari.maximumPoolSize=5logging.pattern.console=%-5level %logger{36} - %msg%n## MySQL
#spring.datasource.url=jdbc:mysql://192.168.1.4:3306/test
#spring.datasource.username=mkyong
#spring.datasource.password=password# Oracle
#spring.datasource.url=jdbc:oracle:thin:@localhost:1521:orcl
#spring.datasource.username=system
#spring.datasource.password=Password123 

7.开始 Spring Boot

7.1 启动 Spring Boot 应用程序,测试 CRUD。

StartApplication.java

 package com.mkyong;import com.mkyong.repository.BookRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.jdbc.core.JdbcTemplate;import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;@SpringBootApplication
public class StartApplication implements CommandLineRunner {private static final Logger log = LoggerFactory.getLogger(StartApplication.class);@AutowiredJdbcTemplate jdbcTemplate;@Autowired//@Qualifier("jdbcBookRepository")              // Test JdbcTemplate@Qualifier("namedParameterJdbcBookRepository")  // Test NamedParameterJdbcTemplateprivate BookRepository bookRepository;public static void main(String[] args) {SpringApplication.run(StartApplication.class, args);}@Overridepublic void run(String... args) {log.info("StartApplication...");runJDBC();}void runJDBC() {log.info("Creating tables for testing...");jdbcTemplate.execute("DROP TABLE books IF EXISTS");jdbcTemplate.execute("CREATE TABLE books(" +"id SERIAL, name VARCHAR(255), price NUMERIC(15, 2))");List<Book> books = Arrays.asList(new Book("Thinking in Java", new BigDecimal("46.32")),new Book("Mkyong in Java", new BigDecimal("1.99")),new Book("Getting Clojure", new BigDecimal("37.3")),new Book("Head First Android Development", new BigDecimal("41.19")));log.info("[SAVE]");books.forEach(book -> {log.info("Saving...{}", book.getName());bookRepository.save(book);});// countlog.info("[COUNT] Total books: {}", bookRepository.count());// find alllog.info("[FIND_ALL] {}", bookRepository.findAll());// find by idlog.info("[FIND_BY_ID] :2L");Book book = bookRepository.findById(2L).orElseThrow(IllegalArgumentException::new);log.info("{}", book);// find by name (like) and pricelog.info("[FIND_BY_NAME_AND_PRICE] : like '%Java%' and price <= 10");log.info("{}", bookRepository.findByNameAndPrice("Java", new BigDecimal(10)));// get name (string) by idlog.info("[GET_NAME_BY_ID] :1L = {}", bookRepository.getNameById(1L));// updatelog.info("[UPDATE] :2L :99.99");book.setPrice(new BigDecimal("99.99"));log.info("rows affected: {}", bookRepository.update(book));// deletelog.info("[DELETE] :3L");log.info("rows affected: {}", bookRepository.deleteById(3L));// find alllog.info("[FIND_ALL] {}", bookRepository.findAll());}} 

8.演示

 $ mvn spring-boot:runINFO  com.mkyong.StartApplication - Started StartApplication in 1.051 seconds (JVM running for 1.3)
INFO  com.mkyong.StartApplication - StartApplication...
INFO  com.mkyong.StartApplication - Creating tables for testing...
DEBUG com.zaxxer.hikari.HikariConfig - HikariPool-1 - configuration:
DEBUG com.zaxxer.hikari.HikariConfig - allowPoolSuspension.............false
DEBUG com.zaxxer.hikari.HikariConfig - autoCommit......................true
DEBUG com.zaxxer.hikari.HikariConfig - catalog.........................none
DEBUG com.zaxxer.hikari.HikariConfig - connectionInitSql...............none
DEBUG com.zaxxer.hikari.HikariConfig - connectionTestQuery.............none
DEBUG com.zaxxer.hikari.HikariConfig - connectionTimeout...............20000
DEBUG com.zaxxer.hikari.HikariConfig - dataSource......................none
DEBUG com.zaxxer.hikari.HikariConfig - dataSourceClassName.............none
DEBUG com.zaxxer.hikari.HikariConfig - dataSourceJNDI..................none
DEBUG com.zaxxer.hikari.HikariConfig - dataSourceProperties............{password=<masked>}
DEBUG com.zaxxer.hikari.HikariConfig - driverClassName................."org.h2.Driver"
DEBUG com.zaxxer.hikari.HikariConfig - healthCheckProperties...........{}
DEBUG com.zaxxer.hikari.HikariConfig - healthCheckRegistry.............none
DEBUG com.zaxxer.hikari.HikariConfig - idleTimeout.....................600000
DEBUG com.zaxxer.hikari.HikariConfig - initializationFailTimeout.......1
DEBUG com.zaxxer.hikari.HikariConfig - isolateInternalQueries..........false
DEBUG com.zaxxer.hikari.HikariConfig - jdbcUrl.........................jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
DEBUG com.zaxxer.hikari.HikariConfig - leakDetectionThreshold..........0
DEBUG com.zaxxer.hikari.HikariConfig - maxLifetime.....................1800000
DEBUG com.zaxxer.hikari.HikariConfig - maximumPoolSize.................5
DEBUG com.zaxxer.hikari.HikariConfig - metricRegistry..................none
DEBUG com.zaxxer.hikari.HikariConfig - metricsTrackerFactory...........none
DEBUG com.zaxxer.hikari.HikariConfig - minimumIdle.....................5
DEBUG com.zaxxer.hikari.HikariConfig - password........................<masked>
DEBUG com.zaxxer.hikari.HikariConfig - poolName........................"HikariPool-1"
DEBUG com.zaxxer.hikari.HikariConfig - readOnly........................false
DEBUG com.zaxxer.hikari.HikariConfig - registerMbeans..................false
DEBUG com.zaxxer.hikari.HikariConfig - scheduledExecutor...............none
DEBUG com.zaxxer.hikari.HikariConfig - schema..........................none
DEBUG com.zaxxer.hikari.HikariConfig - threadFactory...................internal
DEBUG com.zaxxer.hikari.HikariConfig - transactionIsolation............default
DEBUG com.zaxxer.hikari.HikariConfig - username........................"sa"
DEBUG com.zaxxer.hikari.HikariConfig - validationTimeout...............5000
INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:testdb user=SA
INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.INFO  com.mkyong.StartApplication - [SAVE]
INFO  com.mkyong.StartApplication - Saving...Thinking in Java
INFO  com.mkyong.StartApplication - Saving...Mkyong in Java
INFO  com.mkyong.StartApplication - Saving...Getting Clojure
INFO  com.mkyong.StartApplication - Saving...Head First Android DevelopmentINFO  com.mkyong.StartApplication - [COUNT] Total books: 4INFO  com.mkyong.StartApplication - [FIND_ALL] 
[Book{id=1, name='Thinking in Java', price=46.32}, 
Book{id=2, name='Mkyong in Java', price=1.99}, 
Book{id=3, name='Getting Clojure', price=37.30}, 
Book{id=4, name='Head First Android Development', price=41.19}]INFO  com.mkyong.StartApplication - [FIND_BY_ID] :2L
INFO  com.mkyong.StartApplication - Book{id=2, name='Mkyong in Java', price=1.99}INFO  com.mkyong.StartApplication - [FIND_BY_NAME_AND_PRICE] : like '%Java%' and price <= 10
INFO  com.mkyong.StartApplication - [Book{id=2, name='Mkyong in Java', price=1.99}]INFO  com.mkyong.StartApplication - [GET_NAME_BY_ID] :1L = Thinking in JavaINFO  com.mkyong.StartApplication - [UPDATE] :2L :99.99
INFO  com.mkyong.StartApplication - rows affected: 1INFO  com.mkyong.StartApplication - [DELETE] :3L
INFO  com.mkyong.StartApplication - rows affected: 1INFO  com.mkyong.StartApplication - [FIND_ALL] 
[Book{id=1, name='Thinking in Java', price=46.32},
Book{id=2, name='Mkyong in Java', price=99.99}, 
Book{id=4, name='Head First Android Development', price=41.19}]INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Before shutdown stats (total=1, active=0, idle=1, waiting=0)
DEBUG com.zaxxer.hikari.pool.PoolBase - HikariPool-1 - Closing connection conn0: url=jdbc:h2:mem:testdb user=SA: (connection evicted)
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - After shutdown stats (total=0, active=0, idle=0, waiting=0)
INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed. 

下载源代码

$ git clone https://github.com/mkyong/spring-boot.git
$ cd spring-jdbc
$ mvn spring-boot:run

参考

  • JDBC 可调用语句-存储过程输出参数示例
  • 春季 JDBC 文档
  • 使用 SQL 数据库
  • 常用应用属性
  • Spring Boot+Spring Data JPA+Oracle 示例
  • 鼠标指针
  • Java JDBC 教程

Spring Boot JDBC + MySQL + HikariCP 的例子

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-jdbc-mysql-hikaricp-example/

在这篇文章中,我们将向您展示如何创建一个 Spring Boot JDBC 应用+ MySQL 和 HikariCP。

本文中使用的工具:

  1. Spring Boot 1.5.1 .版本
  2. MySQL 5.7.x
  3. HikariCP 2.6
  4. 专家
  5. Java 8

Note
Related – Spring Boot JDBC + Oracle database + Commons DBCP2 example

1.项目结构

一个标准的 Maven 项目结构。

spring boot jdbc directory ## 2.项目依赖性

为 JDBC 应用程序声明一个spring-boot-starter-jdbc

pom.xml

 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>spring-boot-jdbc</artifactId><packaging>jar</packaging><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.1.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- exclude tomcat jdbc connection pool, use HikariCP --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId><exclusions><exclusion><groupId>org.apache.tomcat</groupId><artifactId>tomcat-jdbc</artifactId></exclusion></exclusions></dependency><!-- exclude tomcat-jdbc, Spring Boot will use HikariCP automatically  --><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>2.6.0</version></dependency><!-- For MySQL --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.40</version></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project> 

Terminal

 $ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building spring-boot-jdbc 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.10:tree (default-cli) @ spring-boot-jdbc ---
[INFO] com.mkyong:spring-boot-jdbc:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter:jar:1.5.1.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot:jar:1.5.1.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-context:jar:4.3.6.RELEASE:compile
[INFO] |  |     +- org.springframework:spring-aop:jar:4.3.6.RELEASE:compile
[INFO] |  |     \- org.springframework:spring-expression:jar:4.3.6.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-autoconfigure:jar:1.5.1.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-logging:jar:1.5.1.RELEASE:compile
[INFO] |  |  +- ch.qos.logback:logback-classic:jar:1.1.9:compile
[INFO] |  |  |  \- ch.qos.logback:logback-core:jar:1.1.9:compile
[INFO] |  |  +- org.slf4j:jcl-over-slf4j:jar:1.7.22:compile
[INFO] |  |  +- org.slf4j:jul-to-slf4j:jar:1.7.22:compile
[INFO] |  |  \- org.slf4j:log4j-over-slf4j:jar:1.7.22:compile
[INFO] |  +- org.springframework:spring-core:jar:4.3.6.RELEASE:compile
[INFO] |  \- org.yaml:snakeyaml:jar:1.17:runtime
[INFO] +- org.springframework.boot:spring-boot-starter-jdbc:jar:1.5.1.RELEASE:compile
[INFO] |  \- org.springframework:spring-jdbc:jar:4.3.6.RELEASE:compile
[INFO] |     +- org.springframework:spring-beans:jar:4.3.6.RELEASE:compile
[INFO] |     \- org.springframework:spring-tx:jar:4.3.6.RELEASE:compile
[INFO] +- com.zaxxer:HikariCP:jar:2.6.0:compile
[INFO] |  \- org.slf4j:slf4j-api:jar:1.7.22:compile
[INFO] \- mysql:mysql-connector-java:jar:5.1.40:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.164 s
[INFO] Finished at: 2017-02-12T23:42:47+08:00
[INFO] Final Memory: 20M/309M
[INFO] ------------------------------------------------------------------------ 

Database Connection Pooling
Spring Boot uses Tomcat pooling tomcat-jdbc by default, and follow this sequence to find the connection pool :

 Tomcat pool -->> - HikariCP -->>  Commons DBCP -->>  Commons DBCP2 

阅读 Spring Boot 官方文档—连接到生产数据库

3.JDBC 模板

3.1 Spring Boot 将自动注册一个JdbcTemplate bean,通过@Autowired注入它

CustomerRepository.java

 package com.mkyong.dao;import com.mkyong.model.Customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;import java.util.Date;
import java.util.List;@Repository
public class CustomerRepository {@Autowiredprivate JdbcTemplate jdbcTemplate;// Find all customers, thanks Java 8, you can create a custom RowMapper like this : public List<Customer> findAll() {List<Customer> result = jdbcTemplate.query("SELECT id, name, email, created_date FROM customer",(rs, rowNum) -> new Customer(rs.getInt("id"),rs.getString("name"), rs.getString("email"), rs.getDate("created_date")));return result;}// Add new customerpublic void addCustomer(String name, String email) {jdbcTemplate.update("INSERT INTO customer(name, email, created_date) VALUES (?,?,?)",name, email, new Date());}} 

3.2 客户模型。

Customer.java

 package com.mkyong.model;import java.util.Date;public class Customer {int id;String name;String email;Date date;public Customer(int id, String name, String email, Date date) {this.id = id;this.name = name;this.email = email;this.date = date;}//getters and setters and toString...
} 

4.数据库初始化

Spring boot 默认启用数据源初始化器,并从类路径的根加载 SQL 脚本(schema.sqldata.sql)。

4.1 创建一个customer表。

schema.sql

 DROP TABLE IF EXISTS customer;
CREATE TABLE customer (id INT NOT NULL AUTO_INCREMENT,name VARCHAR(100) NOT NULL,email VARCHAR(100) NOT NULL,created_date DATE NOT NULL,PRIMARY KEY (id)); 

4.2 在customer表中插入 3 行。

data.sql

 INSERT INTO customer(name,email,created_date)VALUES('mkyong','111@yahoo.com', '2017-02-11');
INSERT INTO customer(name,email,created_date)VALUES('yflow','222@yahoo.com', '2017-02-12');
INSERT INTO customer(name,email,created_date)VALUES('zilap','333@yahoo.com', '2017-02-13'); 

Note
For detail, please refer to this official article – Spring Database initialization

4.3 要记录上述 SQL 脚本,请启用org.springframework.jdbc的调试

logback.xml

 <?xml version="1.0" encoding="UTF-8"?>
<configuration><statusListener class="ch.qos.logback.core.status.NopStatusListener" /><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><layout class="ch.qos.logback.classic.PatternLayout"><Pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</Pattern></layout></appender><logger name="org.springframework.jdbc" level="error" additivity="false"><appender-ref ref="STDOUT"/></logger><logger name="com.mkyong" level="error" additivity="false"><appender-ref ref="STDOUT"/></logger><root level="error"><appender-ref ref="STDOUT"/></root></configuration> 

5.配置

配置 MySQL 和 HikariCP 设置。

application.properties

 #disbale Spring banner
spring.main.banner-mode=off# Loads SQL scripts? schema.sql and data.sql
#spring.datasource.initialize=truespring.datasource.url=jdbc:mysql://localhost/mkyong?useSSL=false
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver# HikariCP settings
# spring.datasource.hikari.*#60 sec
spring.datasource.hikari.connection-timeout=60000
# max 5
spring.datasource.hikari.maximum-pool-size=5 

6.@SpringBootApplication

Spring Boot 控制台或CommandLineRunner应用程序,接受参数来执行“显示”或“插入”功能。

SpringBootConsoleApplication.java

 package com.mkyong;import com.mkyong.dao.CustomerRepository;
import com.mkyong.model.Customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;import javax.sql.DataSource;
import java.util.List;import static java.lang.System.exit;@SpringBootApplication
public class SpringBootConsoleApplication implements CommandLineRunner {@AutowiredDataSource dataSource;@Autowiredprivate CustomerRepository customerRepository;public static void main(String[] args) throws Exception {SpringApplication.run(SpringBootConsoleApplication.class, args);}@Overridepublic void run(String... args) throws Exception {System.out.println("DATASOURCE = " + dataSource);// If you want to check the HikariDataSource settings//HikariDataSource newds = (HikariDataSource)dataSource;//System.out.println("DATASOURCE = " + newds.getMaximumPoolSize());if (args.length <= 0) {System.err.println("[Usage] java xxx.jar {insert name email | display}");} else {if (args[0].equalsIgnoreCase("insert")) {System.out.println("Add customer...");String name = args[1];String email = args[2];customerRepository.addCustomer(name, email);}if (args[0].equalsIgnoreCase("display")) {System.out.println("Display all customers...");List<Customer> list = customerRepository.findAll();list.forEach(x -> System.out.println(x));}System.out.println("Done!");}exit(0);}
} 

完成了。

7.演示

Terminal

 $ mvn package# 1\. The database is initialized, the table is created, data is inserted
$ java -jar target/spring-boot-jdbc-1.0.jarDATASOURCE = HikariDataSource (HikariPool-1)
[Usage] java xxx.jar {insert name email | display}# 2\. Disable database initialize process, and insert a new customer
$ java -Dspring.datasource.initialize=false -jar target/spring-boot-jdbc-1.0.jar insert newUser newPasswordDATASOURCE = HikariDataSource (null)
Add customer...
Done!# 3\. Display all customers
$ java -Dspring.datasource.initialize=false -jar target/spring-boot-jdbc-1.0.jar display
DATASOURCE = HikariDataSource (null)
Display all customers...
Customer{id=1, name='mkyong', email='111@yahoo.com', date=2017-02-11}
Customer{id=2, name='yflow', email='222@yahoo.com', date=2017-02-12}
Customer{id=3, name='zilap', email='333@yahoo.com', date=2017-02-13}
Customer{id=4, name='newUser', email='newPassword', date=2017-02-12}
Done! 

下载源代码

Download – spring-boot-jdbc-example.zip (7 KB)

参考

  1. Spring Boot——使用 SQL 数据库
  2. Spring Boot–数据库初始化
  3. Spring Boot 常用应用属性
  4. Spring Boot–数据源构建器
  5. 鼠标指针

connection pool hikaricp jdbc mysql spring boot spring jdbc

Spring Boot JDBC + Oracle 数据库+ Commons DBCP2 示例

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-jdbc-oracle-database-commons-dbcp2-example/

在本文中,我们将向您展示如何创建一个 Spring Boot JDBC 应用程序+ Oracle 数据库+ Commons DBCP2 连接池。

本文中使用的工具:

  1. Spring Boot 1.5.1 .版本
  2. Oracle 数据库 11g 快速版
  3. Oracle JDBC 驱动程序 ojdbc7.jar
  4. 通用 DBCP2 2.1.1
  5. 专家
  6. Java 8

Note
Related – Spring Boot JDBC + MySQL + HikariCP example

1.项目结构

一个标准的 Maven 项目结构。

## 2.项目依赖性

Download and Install Oracle JDBC driver.
Oracle license restriction, you can’t get the Oracle JDBC driver from the public Maven repository. Instead, you need to go the Oracle website to download the driver and install into the Local Maven repository manually.

声明 Spring Boot JDBC spring-boot-starter-jdbc、Oracle JDBC 驱动程序(手动安装)ojdbc7和公共 DBCP2 连接池。

pom.xml

 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>spring-boot-jdbc</artifactId><packaging>jar</packaging><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.1.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- Exclude teh default Tomcat connection pool --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId><exclusions><exclusion><groupId>org.apache.tomcat</groupId><artifactId>tomcat-jdbc</artifactId></exclusion></exclusions></dependency><!-- Oracle JDBC driver --><dependency><groupId>com.oracle</groupId><artifactId>ojdbc7</artifactId><version>12.1.0</version></dependency><!-- Common DBCP2 connection pool --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-dbcp2</artifactId><version>2.1.1</version></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project> 

Terminal

 $ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building spring-boot-jdbc 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.10:tree (default-cli) @ spring-boot-jdbc ---
[INFO] com.mkyong:spring-boot-jdbc:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter:jar:1.5.1.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot:jar:1.5.1.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-context:jar:4.3.6.RELEASE:compile
[INFO] |  |     +- org.springframework:spring-aop:jar:4.3.6.RELEASE:compile
[INFO] |  |     \- org.springframework:spring-expression:jar:4.3.6.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-autoconfigure:jar:1.5.1.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-logging:jar:1.5.1.RELEASE:compile
[INFO] |  |  +- ch.qos.logback:logback-classic:jar:1.1.9:compile
[INFO] |  |  |  +- ch.qos.logback:logback-core:jar:1.1.9:compile
[INFO] |  |  |  \- org.slf4j:slf4j-api:jar:1.7.22:compile
[INFO] |  |  +- org.slf4j:jcl-over-slf4j:jar:1.7.22:compile
[INFO] |  |  +- org.slf4j:jul-to-slf4j:jar:1.7.22:compile
[INFO] |  |  \- org.slf4j:log4j-over-slf4j:jar:1.7.22:compile
[INFO] |  +- org.springframework:spring-core:jar:4.3.6.RELEASE:compile
[INFO] |  \- org.yaml:snakeyaml:jar:1.17:runtime
[INFO] +- org.springframework.boot:spring-boot-starter-jdbc:jar:1.5.1.RELEASE:compile
[INFO] |  \- org.springframework:spring-jdbc:jar:4.3.6.RELEASE:compile
[INFO] |     +- org.springframework:spring-beans:jar:4.3.6.RELEASE:compile
[INFO] |     \- org.springframework:spring-tx:jar:4.3.6.RELEASE:compile
[INFO] +- com.oracle:ojdbc7:jar:12.1.0:compile
[INFO] \- org.apache.commons:commons-dbcp2:jar:2.1.1:compile
[INFO]    +- org.apache.commons:commons-pool2:jar:2.4.2:compile
[INFO]    \- commons-logging:commons-logging:jar:1.2:compile
[INFO] ------------------------------------------------------------------------ 

Database Connection Pooling
Spring Boot uses Tomcat pooling tomcat-jdbc by default, and follow this sequence to find the connection pool :

 Tomcat pool -->> - HikariCP -->>  Commons DBCP -->>  Commons DBCP2 

阅读 Spring Boot 官方文档—连接到生产数据库

3.JDBC 模板

3.1 Spring Boot 会自动注册一个JdbcTemplate bean,只需将它注入你的 bean 中。

CustomerRepository.java

 package com.mkyong.dao;import com.mkyong.model.Customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;import java.util.List;@Repository
public class CustomerRepository {@Autowiredprivate JdbcTemplate jdbcTemplate;// thanks Java 8, look the custom RowMapperpublic List<Customer> findAll() {List<Customer> result = jdbcTemplate.query("SELECT id, name, email, created_date FROM customer",(rs, rowNum) -> new Customer(rs.getInt("id"),rs.getString("name"), rs.getString("email"), rs.getDate("created_date")));return result;}} 

3.2 客户模型。

Customer.java

 package com.mkyong.model;import java.util.Date;public class Customer {int id;String name;String email;Date date;public Customer(int id, String name, String email, Date date) {this.id = id;this.name = name;this.email = email;this.date = date;}//getters and setters and toString...
} 

4.数据库初始化

默认情况下,Spring boot 启用数据源初始化器,并从类路径的根加载 SQL 脚本–schema.sqldata.sql

4.1 创建customer表的 SQL 脚本。

schema.sql

 CREATE TABLE CUSTOMER(
ID NUMBER(10) NOT NULL,
NAME VARCHAR2(100) NOT NULL,
EMAIL VARCHAR2(100) NOT NULL,
CREATED_DATE DATE NOT NULL,
CONSTRAINT CUSTOMER_PK PRIMARY KEY (ID)
); 

4.2 向customer表中插入 3 行的 SQL 脚本。

data.sql

 INSERT INTO "CUSTOMER" (ID, NAME, EMAIL, CREATED_DATE) VALUES(1, 'mkyong','111@yahoo.com', TO_DATE('2017-02-11', 'yyyy-mm-dd'));
INSERT INTO "CUSTOMER" (ID, NAME, EMAIL, CREATED_DATE) VALUES(2, 'yflow','222@yahoo.com', TO_DATE('2017-02-12', 'yyyy-mm-dd'));
INSERT INTO "CUSTOMER" (ID, NAME, EMAIL, CREATED_DATE) VALUES(3, 'zilap','333@yahoo.com', TO_DATE('2017-02-13', 'yyyy-mm-dd')); 

Note
Read this – Spring Database initialization

5.配置

配置 Oracle 和 dbcp2 设置。

application.properties

 spring.main.banner-mode=off# Set true for first time db initialization.
spring.datasource.initialize=truespring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=system
spring.datasource.password=password
spring.datasource.driver-class-oracle.jdbc.driver.OracleDriver# dbcp2 settings
# spring.datasource.dbcp2.*spring.datasource.dbcp2.initial-size=7
spring.datasource.dbcp2.max-total=20
spring.datasource.dbcp2.pool-prepared-statements=true 

6.@SpringBootApplication

Spring Boot 命令行应用程序

SpringBootConsoleApplication.java

 package com.mkyong;import com.mkyong.dao.CustomerRepository;
import com.mkyong.model.Customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;import javax.sql.DataSource;
import java.util.List;import static java.lang.System.exit;@SpringBootApplication
public class SpringBootConsoleApplication implements CommandLineRunner {@AutowiredDataSource dataSource;@AutowiredCustomerRepository customerRepository;public static void main(String[] args) throws Exception {SpringApplication.run(SpringBootConsoleApplication.class, args);}@Overridepublic void run(String... args) throws Exception {System.out.println("DATASOURCE = " + dataSource);/// Get dbcp2 datasource settings// BasicDataSource newds = (BasicDataSource) dataSource;// System.out.println("BasicDataSource = " + newds.getInitialSize());System.out.println("Display all customers...");List<Customer> list = customerRepository.findAll();list.forEach(x -> System.out.println(x));System.out.println("Done!");exit(0);}
} 

7.演示

运行它,Spring Boot 自动加载schema.sqldata.sql脚本,并显示结果。

Terminal

 DATASOURCE = org.apache.commons.dbcp2.BasicDataSource@4eb386df
Display all customers...
Customer{id=1, name='mkyong', email='111@yahoo.com', date=2017-02-11}
Customer{id=2, name='yflow', email='222@yahoo.com', date=2017-02-12}
Customer{id=3, name='zilap', email='333@yahoo.com', date=2017-02-13}
Done! 

如果在调试会话中设置了断点,请查看 Oracle web admin 会话页。

下载源代码

Download – spring-boot-jdbc-oracle-example.zip (7 KB)

参考

  1. Maven 安装甲骨文 JDBC 驱动
  2. 通过 JDBC 驱动程序连接到 Oracle 数据库
  3. Spring Boot——使用 SQL 数据库
  4. Spring Boot–数据库初始化
  5. Spring Boot 常用应用属性
  6. OracleDriver 文档
  7. Oracle 数据库 12.1.0.2 JDBC 驱动& UCP 下载
  8. 在 Oracle 数据库中使用 Java】
  9. Commons DBCP2 配置参数

connection pool dbcp2 jdbc oracle spring boot spring jdbc

Spring Boot·JDBC 存储过程示例

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-jdbc-stored-procedure-examples/

spring jdbc SimpleJdbcCall

在本教程中,我们将向您展示如何使用 Spring Boot·JDBCSimpleJdbcCall从 Oracle 数据库中调用存储过程和存储函数。

使用的技术:

  • Spring Boot 2.1.2 .版本
  • 春季 JDBC 5.1.4 .发布
  • Oracle 数据库 19c
  • HikariCP 3.2.0
  • maven3
  • Java 8

JdbcTemplate不同,Spring Boot 没有自动创建任何SimpleJdbcCall,我们必须手动创建它。

Note
This example extends the previous Spring Boot JDBC examples, adds support for SimpleJdbcCall

1.测试数据

1.1 创建一个表,保存 4 本书进行测试。

 CREATE TABLE BOOKS(ID NUMBER GENERATED ALWAYS as IDENTITY(START with 1 INCREMENT by 1),NAME VARCHAR2(100) NOT NULL,PRICE NUMBER(15, 2) NOT NULL,CONSTRAINT book_pk PRIMARY KEY (ID)
); 
 List<Book> books = Arrays.asList(new Book("Thinking in Java", new BigDecimal("46.32")),new Book("Mkyong in Java", new BigDecimal("1.99")),new Book("Getting Clojure", new BigDecimal("37.3")),new Book("Head First Android Development", new BigDecimal("41.19")));books.forEach(book -> {log.info("Saving...{}", book.getName());bookRepository.save(book);}); 

2.存储过程

2.1 返回单个结果的存储过程。

 CREATE OR REPLACE PROCEDURE get_book_by_id(p_id IN BOOKS.ID%TYPE,o_name OUT BOOKS.NAME%TYPE,o_price OUT BOOKS.PRICE%TYPE)ASBEGINSELECT NAME , PRICE INTO o_name, o_price from BOOKS WHERE ID = p_id;END; 

2.2 我们可以通过@PostConstruct初始化SimpleJdbcCall

StoredProcedure1.java

 package com.mkyong.sp;import com.mkyong.Book;
import com.mkyong.repository.BookRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.Map;
import java.util.Optional;@Component
public class StoredProcedure1 {private static final Logger log = LoggerFactory.getLogger(StoredProcedure1.class);@Autowired@Qualifier("jdbcBookRepository")private BookRepository bookRepository;@Autowiredprivate JdbcTemplate jdbcTemplate;private SimpleJdbcCall simpleJdbcCall;// init SimpleJdbcCall@PostConstructvoid init() {// o_name and O_NAME, samejdbcTemplate.setResultsMapCaseInsensitive(true);simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate).withProcedureName("get_book_by_id");}private static final String SQL_STORED_PROC = ""+ " CREATE OR REPLACE PROCEDURE get_book_by_id "+ " ("+ "  p_id IN BOOKS.ID%TYPE,"+ "  o_name OUT BOOKS.NAME%TYPE,"+ "  o_price OUT BOOKS.PRICE%TYPE"+ " ) AS"+ " BEGIN"+ "  SELECT NAME, PRICE INTO o_name, o_price from BOOKS WHERE ID = p_id;"+ " END;";public void start() {log.info("Creating Store Procedures and Function...");jdbcTemplate.execute(SQL_STORED_PROC);/* Test Stored Procedure */Book book = findById(2L).orElseThrow(IllegalArgumentException::new);// Book{id=2, name='Mkyong in Java', price=1.99}System.out.println(book);}Optional<Book> findById(Long id) {SqlParameterSource in = new MapSqlParameterSource().addValue("p_id", id);Optional result = Optional.empty();try {Map out = simpleJdbcCall.execute(in);if (out != null) {Book book = new Book();book.setId(id);book.setName((String) out.get("O_NAME"));book.setPrice((BigDecimal) out.get("O_PRICE"));result = Optional.of(book);}} catch (Exception e) {// ORA-01403: no data found, or any java.sql.SQLExceptionSystem.err.println(e.getMessage());}return result;}} 

3.存储过程#SYS_REFCURSOR

3.1 返回引用游标的存储过程。

 CREATE OR REPLACE PROCEDURE get_book_by_name(p_name IN BOOKS.NAME%TYPE,o_c_book OUT SYS_REFCURSOR)
AS
BEGINOPEN o_c_book FORSELECT * FROM BOOKS WHERE NAME LIKE '%' || p_name || '%';END; 

3.2 BeanPropertyRowMapper将光标结果映射到book对象。

StoredProcedure2.java

 package com.mkyong.sp;import com.mkyong.Book;
import com.mkyong.repository.BookRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.List;
import java.util.Map;@Component
public class StoredProcedure2 {private static final Logger log = LoggerFactory.getLogger(StoredProcedure2.class);@Autowired@Qualifier("jdbcBookRepository")private BookRepository bookRepository;@Autowiredprivate JdbcTemplate jdbcTemplate;private SimpleJdbcCall simpleJdbcCallRefCursor;// init SimpleJdbcCall@PostConstructpublic void init() {// o_name and O_NAME, samejdbcTemplate.setResultsMapCaseInsensitive(true);// Convert o_c_book SYS_REFCURSOR to List<Book>simpleJdbcCallRefCursor = new SimpleJdbcCall(jdbcTemplate).withProcedureName("get_book_by_name").returningResultSet("o_c_book",BeanPropertyRowMapper.newInstance(Book.class));}private static final String SQL_STORED_PROC_REF = ""+ " CREATE OR REPLACE PROCEDURE get_book_by_name "+ " ("+ "  p_name IN BOOKS.NAME%TYPE,"+ "  o_c_book OUT SYS_REFCURSOR"+ " ) AS"+ " BEGIN"+ "  OPEN o_c_book FOR"+ "  SELECT * FROM BOOKS WHERE NAME LIKE '%' || p_name || '%';"+ " END;";public void start() {log.info("Creating Store Procedures and Function...");jdbcTemplate.execute(SQL_STORED_PROC_REF);/* Test Stored Procedure RefCursor */List<Book> books = findBookByName("Java");// Book{id=1, name='Thinking in Java', price=46.32}// Book{id=2, name='Mkyong in Java', price=1.99}books.forEach(x -> System.out.println(x));}List<Book> findBookByName(String name) {SqlParameterSource paramaters = new MapSqlParameterSource().addValue("p_name", name);Map out = simpleJdbcCallRefCursor.execute(paramaters);if (out == null) {return Collections.emptyList();} else {return (List) out.get("o_c_book");}}} 

4.存储功能

4.1 为测试创建两个函数。

 CREATE OR REPLACE FUNCTION get_price_by_id(p_id IN BOOKS.ID%TYPE)
RETURN NUMBER
IS o_price BOOKS.PRICE%TYPE;
BEGINSELECT PRICE INTO o_price from BOOKS WHERE ID = p_id;RETURN(o_price);
END;CREATE OR REPLACE FUNCTION get_database_time
RETURN VARCHAR2
IS o_date VARCHAR2(20);
BEGINSELECT TO_CHAR(SYSDATE, 'DD-MON-YYYY HH:MI:SS') INTO o_date FROM dual;RETURN(o_date);
END; 

4.2.对于存储函数,用SimpleJdbcCall.executeFunction调用它

StoredFunction.java

 package com.mkyong.sp;import com.mkyong.repository.BookRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.math.BigDecimal;@Component
public class StoredFunction {private static final Logger log = LoggerFactory.getLogger(StoredFunction.class);@Autowired@Qualifier("jdbcBookRepository")private BookRepository bookRepository;@Autowiredprivate JdbcTemplate jdbcTemplate;private SimpleJdbcCall simpleJdbcCallFunction1;private SimpleJdbcCall simpleJdbcCallFunction2;// init SimpleJdbcCall@PostConstructpublic void init() {jdbcTemplate.setResultsMapCaseInsensitive(true);simpleJdbcCallFunction1 = new SimpleJdbcCall(jdbcTemplate).withFunctionName("get_price_by_id");simpleJdbcCallFunction2 = new SimpleJdbcCall(jdbcTemplate).withFunctionName("get_database_time");}private static final String SQL_STORED_FUNCTION_1 = ""+ " CREATE OR REPLACE FUNCTION get_price_by_id(p_id IN BOOKS.ID%TYPE) "+ " RETURN NUMBER"+ " IS o_price BOOKS.PRICE%TYPE;"+ " BEGIN"+ "  SELECT PRICE INTO o_price from BOOKS WHERE ID = p_id;"+ "  RETURN(o_price);"+ " END;";private static final String SQL_STORED_FUNCTION_2 = ""+ " CREATE OR REPLACE FUNCTION get_database_time "+ " RETURN VARCHAR2"+ " IS o_date VARCHAR2(20);"+ " BEGIN"+ "  SELECT TO_CHAR(SYSDATE, 'DD-MON-YYYY HH:MI:SS') INTO o_date FROM dual;"+ "  RETURN(o_date);"+ " END;";public void start() {log.info("Creating Store Procedures and Function...");jdbcTemplate.execute(SQL_STORED_FUNCTION_1);jdbcTemplate.execute(SQL_STORED_FUNCTION_2);/* Test Stored Function 1 */SqlParameterSource in = new MapSqlParameterSource().addValue("p_id", 3L);BigDecimal price = simpleJdbcCallFunction1.executeFunction(BigDecimal.class, in);System.out.println(price);  // 37.3/* Test Stored Function 2 */String database_time = simpleJdbcCallFunction2.executeFunction(String.class);System.out.println(database_time); // e.g current date, 23-JUL-2019 05:08:44}} 

总而言之:

  • 对于存储过程,SimpleJdbcCall.execute
  • 对于存储功能,SimpleJdbcCall.executeFunction

下载源代码

$ git clone https://github.com/mkyong/spring-boot.git
$ cd spring-jdbc/sp

参考

  • Oracle 创建函数
  • Oracle 存储函数示例
  • Oracle 开发和使用存储过程
  • JDBC 可调用语句-存储过程输出参数示例
  • 春季 JDBC 文档
  • 使用 SQL 数据库
  • Java JDBC 教程
  • 使用引用游标返回记录集

Spring Boot——Jetty 作为嵌入式服务器

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-jetty-as-embedded-server/

默认情况下,Spring Boot 使用 Tomcat 作为默认的嵌入式服务器,要将其更改为 Jetty,只需排除 Tomcat 并包含 Jetty,如下所示:

1.弹簧靴起动器网

pom.xml

 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jetty</artifactId></dependency> 

2.百里香叶

pom.xml

 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jetty</artifactId></dependency> 

查看依赖关系

 $ mvn dependency:tree[INFO] org.springframework.boot:spring-boot-web-thymeleaf:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-thymeleaf:jar:1.4.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:1.4.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:1.4.2.RELEASE:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.1.7:compile
[INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.1.7:compile
[INFO] |  |  |  +- org.slf4j:jcl-over-slf4j:jar:1.7.21:compile
[INFO] |  |  |  +- org.slf4j:jul-to-slf4j:jar:1.7.21:compile
[INFO] |  |  |  \- org.slf4j:log4j-over-slf4j:jar:1.7.21:compile
[INFO] |  |  +- org.springframework:spring-core:jar:4.3.4.RELEASE:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.17:runtime
[INFO] |  +- org.springframework.boot:spring-boot-starter-web:jar:1.4.2.RELEASE:compile
[INFO] |  |  +- org.hibernate:hibernate-validator:jar:5.2.4.Final:compile
[INFO] |  |  |  +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO] |  |  |  +- org.jboss.logging:jboss-logging:jar:3.3.0.Final:compile
[INFO] |  |  |  \- com.fasterxml:classmate:jar:1.3.3:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.4:compile
[INFO] |  |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.4:compile
[INFO] |  |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.8.4:compile
[INFO] |  |  +- org.springframework:spring-web:jar:4.3.4.RELEASE:compile
[INFO] |  |  |  +- org.springframework:spring-aop:jar:4.3.4.RELEASE:compile
[INFO] |  |  |  \- org.springframework:spring-beans:jar:4.3.4.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-webmvc:jar:4.3.4.RELEASE:compile
[INFO] |  |     \- org.springframework:spring-expression:jar:4.3.4.RELEASE:compile
[INFO] |  +- org.thymeleaf:thymeleaf-spring4:jar:2.1.5.RELEASE:compile
[INFO] |  |  +- org.thymeleaf:thymeleaf:jar:2.1.5.RELEASE:compile
[INFO] |  |  |  +- ognl:ognl:jar:3.0.8:compile
[INFO] |  |  |  +- org.javassist:javassist:jar:3.20.0-GA:compile
[INFO] |  |  |  \- org.unbescape:unbescape:jar:1.1.0.RELEASE:compile
[INFO] |  |  \- org.slf4j:slf4j-api:jar:1.7.21:compile
[INFO] |  \- nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:jar:1.4.0:compile
[INFO] |     \- org.codehaus.groovy:groovy:jar:2.4.7:compile
[INFO] +- org.springframework.boot:spring-boot-starter-jetty:jar:1.4.2.RELEASE:compile
[INFO] |  +- org.eclipse.jetty:jetty-servlets:jar:9.3.14.v20161028:compile
[INFO] |  |  +- org.eclipse.jetty:jetty-continuation:jar:9.3.14.v20161028:compile
[INFO] |  |  +- org.eclipse.jetty:jetty-http:jar:9.3.14.v20161028:compile
[INFO] |  |  +- org.eclipse.jetty:jetty-util:jar:9.3.14.v20161028:compile
[INFO] |  |  \- org.eclipse.jetty:jetty-io:jar:9.3.14.v20161028:compile
[INFO] |  +- org.eclipse.jetty:jetty-webapp:jar:9.3.14.v20161028:compile
[INFO] |  |  +- org.eclipse.jetty:jetty-xml:jar:9.3.14.v20161028:compile
[INFO] |  |  \- org.eclipse.jetty:jetty-servlet:jar:9.3.14.v20161028:compile
[INFO] |  |     \- org.eclipse.jetty:jetty-security:jar:9.3.14.v20161028:compile
[INFO] |  |        \- org.eclipse.jetty:jetty-server:jar:9.3.14.v20161028:compile
[INFO] |  +- org.eclipse.jetty.websocket:websocket-server:jar:9.3.14.v20161028:compile
[INFO] |  |  +- org.eclipse.jetty.websocket:websocket-common:jar:9.3.14.v20161028:compile
[INFO] |  |  |  \- org.eclipse.jetty.websocket:websocket-api:jar:9.3.14.v20161028:compile
[INFO] |  |  +- org.eclipse.jetty.websocket:websocket-client:jar:9.3.14.v20161028:compile
[INFO] |  |  \- org.eclipse.jetty.websocket:websocket-servlet:jar:9.3.14.v20161028:compile
[INFO] |  |     \- javax.servlet:javax.servlet-api:jar:3.1.0:compile
[INFO] |  +- org.eclipse.jetty.websocket:javax-websocket-server-impl:jar:9.3.14.v20161028:compile
[INFO] |  |  +- org.eclipse.jetty:jetty-annotations:jar:9.3.14.v20161028:compile
[INFO] |  |  |  +- org.eclipse.jetty:jetty-plus:jar:9.3.14.v20161028:compile
[INFO] |  |  |  +- javax.annotation:javax.annotation-api:jar:1.2:compile
[INFO] |  |  |  +- org.ow2.asm:asm:jar:5.0.1:compile
[INFO] |  |  |  \- org.ow2.asm:asm-commons:jar:5.0.1:compile
[INFO] |  |  |     \- org.ow2.asm:asm-tree:jar:5.0.1:compile
[INFO] |  |  +- org.eclipse.jetty.websocket:javax-websocket-client-impl:jar:9.3.14.v20161028:compile
[INFO] |  |  \- javax.websocket:javax.websocket-api:jar:1.0:compile
[INFO] |  \- org.mortbay.jasper:apache-el:jar:8.0.33:compile
[INFO] +- org.springframework.boot:spring-boot-devtools:jar:1.4.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot:jar:1.4.2.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-context:jar:4.3.4.RELEASE:compile
[INFO] |  \- org.springframework.boot:spring-boot-autoconfigure:jar:1.4.2.RELEASE:compile 

PS 用 Spring Boot 1.4.2.RELEASE 测试

Note
Spring Boot 1.4.2.RELEASE use Jetty 9.3.14.v20161028

参考

  1. Spring Boot——嵌入式 servlet 容器
  2. 码头服务器

Spring Boot + JUnit 5 + Mockito

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-junit-5-mockito/

Spring Boot JUnit 5

在本文中,我们将向您展示如何用 JUnit 5 和 Mockito 进行 Spring Boot 2 集成测试。

  • Spring Boot 2.1.2 .版本
  • JUnit 5
  • Mockito 2
  • maven3

简而言之,从spring-boot-starter-test中排除 junit4,手动包含 JUnit 5 jupiter 引擎,完成。

让我们看看下面的 Spring boot MVC web 应用,以及如何用 JUnit 5 进行单元测试,用 Mockito 框架进行 MVC。

1.专家

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong.spring</groupId><artifactId>testing-junit5-mockito</artifactId><version>1.0</version><properties><java.version>1.8</java.version><junit-jupiter.version>5.3.2</junit-jupiter.version><mockito.version>2.24.0</mockito.version></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version></parent><dependencies><!-- mvc --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- exclude junit 4 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>junit</groupId><artifactId>junit</artifactId></exclusion></exclusions></dependency><!-- junit 5 --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>${junit-jupiter.version}</version><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.22.0</version></plugin></plugins></build></project> 

显示项目依赖关系。

 $ mvn dependency:tree[INFO] com.mkyong.spring:testing-junit5-mockito:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.1.2.RELEASE:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] |  |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.11.1:compile
[INFO] |  |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.11.1:compile
[INFO] |  |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
[INFO] |  |  +- javax.annotation:javax.annotation-api:jar:1.3.2:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.23:runtime
[INFO] |  +- org.springframework.boot:spring-boot-starter-json:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.8:compile
[INFO] |  |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile
[INFO] |  |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.9.8:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.9.8:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.9.8:compile
[INFO] |  |  \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.9.8:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.14:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:9.0.14:compile
[INFO] |  |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.14:compile
[INFO] |  +- org.hibernate.validator:hibernate-validator:jar:6.0.14.Final:compile
[INFO] |  |  +- javax.validation:validation-api:jar:2.0.1.Final:compile
[INFO] |  |  +- org.jboss.logging:jboss-logging:jar:3.3.2.Final:compile
[INFO] |  |  \- com.fasterxml:classmate:jar:1.4.0:compile
[INFO] |  +- org.springframework:spring-web:jar:5.1.4.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-beans:jar:5.1.4.RELEASE:compile
[INFO] |  \- org.springframework:spring-webmvc:jar:5.1.4.RELEASE:compile
[INFO] |     +- org.springframework:spring-aop:jar:5.1.4.RELEASE:compile
[INFO] |     +- org.springframework:spring-context:jar:5.1.4.RELEASE:compile
[INFO] |     \- org.springframework:spring-expression:jar:5.1.4.RELEASE:compile
[INFO] +- org.springframework.boot:spring-boot-starter-test:jar:2.1.2.RELEASE:test
[INFO] |  +- org.springframework.boot:spring-boot-test:jar:2.1.2.RELEASE:test
[INFO] |  +- org.springframework.boot:spring-boot-test-autoconfigure:jar:2.1.2.RELEASE:test
[INFO] |  +- com.jayway.jsonpath:json-path:jar:2.4.0:test
[INFO] |  |  +- net.minidev:json-smart:jar:2.3:test
[INFO] |  |  |  \- net.minidev:accessors-smart:jar:1.2:test
[INFO] |  |  |     \- org.ow2.asm:asm:jar:5.0.4:test
[INFO] |  |  \- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] |  +- org.assertj:assertj-core:jar:3.11.1:test
[INFO] |  +- org.mockito:mockito-core:jar:2.24.0:test
[INFO] |  |  +- net.bytebuddy:byte-buddy:jar:1.9.7:test
[INFO] |  |  +- net.bytebuddy:byte-buddy-agent:jar:1.9.7:test
[INFO] |  |  \- org.objenesis:objenesis:jar:2.6:test
[INFO] |  +- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] |  +- org.hamcrest:hamcrest-library:jar:1.3:test
[INFO] |  +- org.skyscreamer:jsonassert:jar:1.5.0:test
[INFO] |  |  \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test
[INFO] |  +- org.springframework:spring-core:jar:5.1.4.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-jcl:jar:5.1.4.RELEASE:compile
[INFO] |  +- org.springframework:spring-test:jar:5.1.4.RELEASE:test
[INFO] |  \- org.xmlunit:xmlunit-core:jar:2.6.2:test
[INFO] |     \- javax.xml.bind:jaxb-api:jar:2.3.1:test
[INFO] |        \- javax.activation:javax.activation-api:jar:1.2.0:test
[INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.3.2:test
[INFO] |  +- org.apiguardian:apiguardian-api:jar:1.0.0:test
[INFO] |  +- org.junit.platform:junit-platform-engine:jar:1.3.2:test
[INFO] |  |  +- org.junit.platform:junit-platform-commons:jar:1.3.2:test
[INFO] |  |  \- org.opentest4j:opentest4j:jar:1.1.1:test
[INFO] |  \- org.junit.jupiter:junit-jupiter-api:jar:5.3.2:test
[INFO] \- org.springframework.boot:spring-boot-devtools:jar:2.1.2.RELEASE:compile (optional)
[INFO]    +- org.springframework.boot:spring-boot:jar:2.1.2.RELEASE:compile
[INFO]    \- org.springframework.boot:spring-boot-autoconfigure:jar:2.1.2.RELEASE:compile 

2.测试 Spring Boot + JUnit 5 + Mockito。

2.1 测试下列弹簧部件。

HelloServiceImpl.java

 package com.mkyong.core.services;import com.mkyong.core.repository.HelloRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class HelloServiceImpl implements HelloService {@AutowiredHelloRepository helloRepository;@Overridepublic String get() {return helloRepository.get();}} 

HelloRepositoryImpl.java

 package com.mkyong.core.repository;import org.springframework.stereotype.Repository;@Repository
public class HelloRepositoryImpl implements HelloRepository {@Overridepublic String get() {return "Hello JUnit 5";}
} 

2.2 JUnit 5

HelloServiceTest.java

 package com.mkyong.core.services;import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import static org.junit.jupiter.api.Assertions.assertEquals;@SpringBootTest
public class HelloServiceTest {@AutowiredHelloService helloService;@DisplayName("Test Spring @Autowired Integration")@Testvoid testGet() {assertEquals("Hello JUnit 5", helloService.get());}} 

2.3 Mockito.

HelloServiceMockTest.java

 package com.mkyong.core.services;import com.mkyong.core.repository.HelloRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;@SpringBootTest
public class HelloServiceMockTest {@Mockprivate HelloRepository helloRepository;@InjectMocks // auto inject helloRepositoryprivate HelloService helloService = new HelloServiceImpl();@BeforeEachvoid setMockOutput() {when(helloRepository.get()).thenReturn("Hello Mockito From Repository");}@DisplayName("Test Mock helloService + helloRepository")@Testvoid testGet() {assertEquals("Hello Mockito From Repository", helloService.get());}} 

3.测试 Spring MVC 控制器。

3.1 MVC 控制器。

MainController.java

 package com.mkyong.core.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
public class MainController {@ResponseBody@GetMapping("/")public String hello() {return "Hello Controller";}} 

3.2 JUnit 5 和 MVC 测试。

MainControllerTest.java

 package com.mkyong.core.controller;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.ResponseEntity;import java.net.URL;import static org.junit.jupiter.api.Assertions.assertEquals;@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class MainControllerTest {// bind the above RANDOM_PORT@LocalServerPortprivate int port;@Autowiredprivate TestRestTemplate restTemplate;@Testpublic void getHello() throws Exception {ResponseEntity<String> response = restTemplate.getForEntity(new URL("http://localhost:" + port + "/").toString(), String.class);assertEquals("Hello Controller", response.getBody());}} 

完成了。

下载源代码

$ git clone https://github.com/mkyong/spring-boot.git
$ cd testing-junit5-mockito
$ mvn test

参考

  • Spring Boot 测试
  • Mockito:为什么不应该对 Autowire 字段使用 InjectMocks 注释
  • JUnit 5 用户指南

Spring Boot Log4j 2 示例

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-log4j-2-example/

spring boot log4j 2

在本教程中,我们将向您展示如何在 Spring Boot 框架中使用 Apache Log4j 2 。

使用的技术:

  • Spring Boot 2.1.2 .版本
  • 弹簧 5.1.4 释放
  • Log4j 2.11.1
  • maven3
  • Java 8

1.项目目录

project directory

2.专家

关键是排除默认logback,用spring-boot-starter-log4j2包含log4j

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>logging-log4j2</artifactId><packaging>jar</packaging><name>Spring Boot log4j2 Example</name><url>https://www.mkyong.com</url><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- exclude logback , add log4j2 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId></dependency><!-- asynchronous loggers --><dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.4.2</version></dependency><!-- for log4j2.yml, need jackson-databind and jackson-dataformat-yaml --><!-- spring-boot-starter-web -> spring-boot-starter-json -> jackson-databind--><!-- included by spring boot<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency>--><dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-yaml</artifactId></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.22.0</version></plugin></plugins></build>
</project> 

显示项目依赖关系。

 $ mvn dependency:tree[INFO] \- org.springframework.boot:spring-boot-starter-log4j2:jar:2.1.2.RELEASE:compile
[INFO]    +- org.apache.logging.log4j:log4j-slf4j-impl:jar:2.11.1:compile <--- slf4j to log4j bridge
[INFO]    |  \- org.apache.logging.log4j:log4j-api:jar:2.11.1:compile
[INFO]    +- org.apache.logging.log4j:log4j-core:jar:2.11.1:compile
[INFO]    +- org.apache.logging.log4j:log4j-jul:jar:2.11.1:compile
[INFO]    \- org.slf4j:jul-to-slf4j:jar:1.7.25:compile 
 $ mvn dependency:tree[INFO] org.springframework.boot:logging-log4j2:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-json:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.8:compile
[INFO] |  |  |  \- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.9.8:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.9.8:compile
[INFO] |  |  \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.9.8:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.14:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:9.0.14:compile
[INFO] |  |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.14:compile
[INFO] |  +- org.hibernate.validator:hibernate-validator:jar:6.0.14.Final:compile
[INFO] |  |  +- javax.validation:validation-api:jar:2.0.1.Final:compile
[INFO] |  |  +- org.jboss.logging:jboss-logging:jar:3.3.2.Final:compile
[INFO] |  |  \- com.fasterxml:classmate:jar:1.4.0:compile
[INFO] |  +- org.springframework:spring-web:jar:5.1.4.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-beans:jar:5.1.4.RELEASE:compile
[INFO] |  \- org.springframework:spring-webmvc:jar:5.1.4.RELEASE:compile
[INFO] |     +- org.springframework:spring-aop:jar:5.1.4.RELEASE:compile
[INFO] |     +- org.springframework:spring-context:jar:5.1.4.RELEASE:compile
[INFO] |     \- org.springframework:spring-expression:jar:5.1.4.RELEASE:compile
[INFO] +- org.springframework.boot:spring-boot-starter-thymeleaf:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.thymeleaf:thymeleaf-spring5:jar:3.0.11.RELEASE:compile
[INFO] |  |  +- org.thymeleaf:thymeleaf:jar:3.0.11.RELEASE:compile
[INFO] |  |  |  +- org.attoparser:attoparser:jar:2.0.5.RELEASE:compile
[INFO] |  |  |  \- org.unbescape:unbescape:jar:1.1.6.RELEASE:compile
[INFO] |  |  \- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] |  \- org.thymeleaf.extras:thymeleaf-extras-java8time:jar:3.0.2.RELEASE:compile
[INFO] +- org.springframework.boot:spring-boot-starter:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.1.2.RELEASE:compile
[INFO] |  +- javax.annotation:javax.annotation-api:jar:1.3.2:compile
[INFO] |  +- org.springframework:spring-core:jar:5.1.4.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-jcl:jar:5.1.4.RELEASE:compile
[INFO] |  \- org.yaml:snakeyaml:jar:1.23:compile
[INFO] +- org.springframework.boot:spring-boot-starter-log4j2:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.apache.logging.log4j:log4j-slf4j-impl:jar:2.11.1:compile
[INFO] |  |  \- org.apache.logging.log4j:log4j-api:jar:2.11.1:compile
[INFO] |  +- org.apache.logging.log4j:log4j-core:jar:2.11.1:compile
[INFO] |  +- org.apache.logging.log4j:log4j-jul:jar:2.11.1:compile
[INFO] |  \- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
[INFO] +- com.lmax:disruptor:jar:3.4.2:compile
[INFO] \- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.9.8:compile
[INFO]    \- com.fasterxml.jackson.core:jackson-core:jar:2.9.8:compile 

3.log4j2.xml

3.1 在项目类路径中创建一个log4j2.xmlsrc/resources/

src/resources/log4j2.xml

 <?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG"><Appenders><Console name="LogToConsole" target="SYSTEM_OUT"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Console><File name="LogToFile" fileName="logs/app.log"><PatternLayout><Pattern>%d %p %c{1.} [%t] %m%n</Pattern></PatternLayout></File></Appenders><Loggers><Logger name="com.mkyong" level="debug" additivity="false"><AppenderRef ref="LogToFile"/><AppenderRef ref="LogToConsole"/></Logger><Logger name="org.springframework.boot" level="error" additivity="false"><AppenderRef ref="LogToConsole"/></Logger><Root level="error"><AppenderRef ref="LogToFile"/><AppenderRef ref="LogToConsole"/></Root></Loggers>
</Configuration> 

3.2 对于log4j2.yml,我们需要包含jackson-databindjackson-dataformat-yaml,因为jackson-databind已经包含在 Spring Boot 启动器中,所以我们只需要包含jackson-dataformat-yaml

pom.xml

 <!-- spring-boot-starter-web -> spring-boot-starter-json -> jackson-databind--><!-- included by spring boot<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency>--><dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-yaml</artifactId></dependency> 

log4j2.yml

 Configuration:status: debugappenders:Console:name: LogToConsolePatternLayout:Pattern: "[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"RollingFile:- name: LogToRollingFilefileName: logs/app.logfilePattern: "logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz"PatternLayout:pattern: "[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"Policies:SizeBasedTriggeringPolicy:size: 10MBDefaultRollOverStrategy:max: 10Loggers:logger:- name: com.mkyonglevel: debugadditivity: falseAppenderRef:- ref: LogToConsole- ref: LogToRollingFileRoot:level: errorAppenderRef:ref: LogToConsole 

4.你好 log4j2

4.1 一个简单的 Spring MVC web 应用,用 log4j2 登录。

HelloController.java

 package com.mkyong;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;import java.util.Arrays;
import java.util.List;@Controller
public class HelloController {private static final Logger logger = LogManager.getLogger(HelloController.class);private List<Integer> num = Arrays.asList(1, 2, 3, 4, 5);@GetMapping("/")public String main(Model model) {// pre-java 8if (logger.isDebugEnabled()) {logger.debug("Hello from Log4j 2 - num : {}", num);}// java 8 lambda, no need to check log levellogger.debug("Hello from Log4j 2 - num : {}", () -> num);model.addAttribute("tasks", num);return "welcome"; //view}private int getNum() {return 100;}} 

4.2 模板

src/resources/templates/welcome.html

 <!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head></head>
<body><h1>Spring Boot + log4j2 example</h1>
<ul><li th:each="task : ${tasks}" th:text="${task}"></li>
</ul></body>
</html> 

5.演示

5.1 启动 Spring Boot

StartApplication.java

 package com.mkyong;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class StartApplication {public static void main(String[] args) {SpringApplication.run(StartApplication.class, args);}} 

http://localhost:8080

demo

查看日志记录:

Terminal

 19:10:08.723 [http-nio-8080-exec-1] DEBUG com.mkyong.HelloController - Hello from Log4j 2 - num : [1, 2, 3, 4, 5]
19:10:08.724 [http-nio-8080-exec-1] DEBUG com.mkyong.HelloController - Hello from Log4j 2 - num : [1, 2, 3, 4, 5] 

6.log4j 2–异步记录器

6.1 要启用异步日志,我们需要包含disruptor

pom.xml

 <dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.4.2</version></dependency> 

6.2 设置系统属性log4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

Terminal

 $ mvn package $ java -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector -jar target/logging-log4j2-1.0.jar019-03-27 19:28:57,185 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@578486a3
2019-03-27 19:28:57,189 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@578486a3,component=AsyncLoggerRingBuffer
2019-03-27 19:28:57,194 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@578486a3,component=StatusLogger
2019-03-27 19:28:57,195 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@578486a3,component=ContextSelector
2019-03-27 19:28:57,195 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@578486a3,component=Loggers,name=org.springframework.boot
2019-03-27 19:28:57,196 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@578486a3,component=Loggers,name=
2019-03-27 19:28:57,196 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@578486a3,component=Loggers,name=com.mkyong
2019-03-27 19:28:57,197 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@578486a3,component=Appenders,name=LogToConsole
2019-03-27 19:28:57,200 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@578486a3,component=Appenders,name=LogToFile 

下载源代码

$ git clone https://github.com/mkyong/spring-boot.git
$ cd logging-log4j2
$ mvn spring-boot:run
Access localhost:8080

$ mvn 包
$ Java-dlog 4j 2 . context selector = org . Apache . logging . log4j . core . async . asyncloggercontextselector-jar target/logging-log4j 2-1.0 . jar
Accesslocalhost:8080

参考

  • Spring Boot 测井
  • 阿帕奇 Log4j 2
  • Apache Log4j 2 教程
  • 用于低延迟记录的异步记录器

Spring Boot 非 web 应用示例

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-non-web-application-example/

在 Spring Boot,要创建一个非 web 应用程序,实现CommandLineRunner并覆盖run方法,例如:

 import org.springframework.boot.CommandLineRunner;@SpringBootApplication
public class SpringBootConsoleApplication implements CommandLineRunner {public static void main(String[] args) throws Exception {SpringApplication.run(SpringBootConsoleApplication.class, args);}//access command line arguments@Overridepublic void run(String... args) throws Exception {//do something}
} 

1.项目结构

一个标准的 Maven 项目结构。

2.项目依赖性

spring-boot-starter

pom.xml

 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>spring-boot-simple</artifactId><packaging>jar</packaging><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.1.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project> 

3.春天

3.1 返回消息的服务。

HelloMessageService.java

 package com.mkyong.service;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;@Service
public class HelloMessageService {@Value("${name:unknown}")private String name;public String getMessage() {return getMessage(name);}public String getMessage(String name) {return "Hello " + name;}} 

application.properties

 name=mkyong 

3.2 CommandLineRunner示例。如果您运行这个 Spring Boot,那么run方法将是入口点。

SpringBootConsoleApplication.java

 package com.mkyong;import com.mkyong.service.HelloMessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.Banner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;import static java.lang.System.exit;@SpringBootApplication
public class SpringBootConsoleApplication implements CommandLineRunner {@Autowiredprivate HelloMessageService helloService;public static void main(String[] args) throws Exception {//disabled banner, don't want to see the spring logoSpringApplication app = new SpringApplication(SpringBootConsoleApplication.class);app.setBannerMode(Banner.Mode.OFF);app.run(args);}// Put your logic here.@Overridepublic void run(String... args) throws Exception {if (args.length > 0) {System.out.println(helloService.getMessage(args[0].toString()));} else {System.out.println(helloService.getMessage());}exit(0);}
} 

4.演示

打包并运行它。

 ## Go to project directory
## package it
$ mvn package$ java -jar target/spring-boot-simple-1.0.jar
Hello mkyong$ java -jar target/spring-boot-simple-1.0.jar "donald trump"
Hello donald trump 

下载源代码

Download – spring-boot-non-web-example.zip (5 KB)

参考

  1. 命令行运行程序 JavaDoc

Tags : CommandLineRunner executable jar jar spring boot

相关文章

  • Spring Boot——开始哪个主班

  • Maven -如何创建一个 Java 项目

  • Spring Boot -应用程序启动时运行代码

  • 如何制作 Java exe 文件或可执行 JAR 文件

  • 如何将清单添加到 Jar 文件中

  • Java 归档工具(JAR)示例

  • Java -从资源文件夹中读取文件

  • 如何用 Maven 创建 jar 文件

  • Gradle -创建一个具有依赖关系的 Jar 文件

  • Spring Boot Hello World 示例- JSP

Spring Boot-基于配置文件的属性和 yaml 示例

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-profile-based-properties-and-yaml-example/

在 Spring Boot,它按以下顺序挑选.properties.yaml文件:

  • application-{profile}.properties和 YAML 的变种
  • application.properties和 YAML 的变种

Note
For detail, sequence and order, please refer to this official Externalized Configuration documentation.

测试:

  • Spring Boot 2.1.2 .版本
  • maven3

1.项目结构

一个标准的 Maven 项目结构。

profile propertiesprofile yaml

2.@配置属性

稍后读取属性或 yaml 文件。

ServerProperties.java

 package com.mkyong.config;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;@Component
@ConfigurationProperties("server")
public class ServerProperties {private String email;private List<Cluster> cluster = new ArrayList<>();public static class Cluster {private String ip;private String path;public String getIp() {return ip;}public void setIp(String ip) {this.ip = ip;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}@Overridepublic String toString() {return "Cluster{" +"ip='" + ip + '\'' +", path='" + path + '\'' +'}';}}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public List<Cluster> getCluster() {return cluster;}public void setCluster(List<Cluster> cluster) {this.cluster = cluster;}@Overridepublic String toString() {return "ServerProperties{" +"email='" + email + '\'' +", cluster=" + cluster +'}';}
} 

3.基于配置文件的属性

多个配置文件.properties示例。

application.properties

 #Logging
logging.level.org.springframework.web=ERROR
logging.level.com.mkyong=ERROR
logging.level.=error#spring
spring.main.banner-mode=off
spring.profiles.active=dev 

application-dev.properties

 #dev environment
server.email: dev@mkyong.com
server.cluster[0].ip=127.0.0.1
server.cluster[0].path=/dev1
server.cluster[1].ip=127.0.0.2
server.cluster[1].path=/dev2
server.cluster[2].ip=127.0.0.3
server.cluster[2].path=/dev3 

application-prod.properties

 #production environment
server.email: prod@mkyong.com
server.cluster[0].ip=192.168.0.1
server.cluster[0].path=/app1
server.cluster[1].ip=192.168.0.2
server.cluster[1].path=/app2
server.cluster[2].ip=192.168.0.3
server.cluster[2].path=/app3 

4.基于配置文件的 YAML

多个配置文件.yml示例。在 YAML,我们可以通过使用“—”分隔符来创建多个概要文件。

application.yml

 logging:level:.: errororg.springframework: ERRORcom.mkyong: ERRORspring:profiles:active: "dev"main:banner-mode: "off"server:email: default@mkyong.com---spring:profiles: dev
server:email: dev@mkyong.comcluster:- ip: 127.0.0.1path: /dev1- ip: 127.0.0.2path: /dev2- ip: 127.0.0.3path: /dev3---spring:profiles: prod
server:email: prod@mkyong.comcluster:- ip: 192.168.0.1path: /app1- ip: 192.168.0.2path: /app2- ip: 192.168.0.3path: /app3 

5.演示

5.1 Spring Boot 应用程序。

Application.java

 package com.mkyong;import com.mkyong.config.ServerProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Application implements CommandLineRunner {@Autowiredprivate ServerProperties serverProperties;@Overridepublic void run(String... args) {System.out.println(serverProperties);}public static void main(String[] args) {SpringApplication.run(Application.class, args);}} 

5.2 打包并运行它。

 $ mvn package# The 'dev' profile is configured in application.properties# Profile : dev , picks application-dev.properties or YAML 
$ java -jar target/spring-boot-profile-1.0.jarServerProperties{email='dev@mkyong.com', cluster=[Cluster{ip='127.0.0.1', path='/dev1'}, Cluster{ip='127.0.0.2', path='/dev2'}, Cluster{ip='127.0.0.3', path='/dev3'}
]}# Profile : prod, picks application-prod.properties or YAML
$ java -jar -Dspring.profiles.active=prod target/spring-boot-profile-1.0.jarServerProperties{email='prod@mkyong.com', cluster=[Cluster{ip='192.168.0.1', path='/app1'}, Cluster{ip='192.168.0.2', path='/app2'}, Cluster{ip='192.168.0.3', path='/app3'}
]}# Profile : abc, a non-exists profile
$ java -jar -Dspring.profiles.active=abc target/spring-boot-profile-1.0.jar
ServerProperties{email='null', cluster=[]} 

Note
Spring Boot, the default profile is default, we can set the profile via spring.profiles.active property.

下载源代码

$ git clone https://github.com/mkyong/spring-boot.git

属性示例
$ cd 配置文件-属性
$ mvn 包

YAML 示例
$ cd 简介-yaml
$mvn 包

参考

  • Spring Boot–属性&配置
  • Spring Boot–个人资料特定属性
  • Spring Boot 简介示例
  • 弹簧轮廓示例
  • Spring Boot 简介示例

Spring Boot 配置文件示例

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-profiles-example/

在本文中,我们将向您展示如何在 Spring Boot 使用@Profile以及如何测试它。

使用的工具:

  1. Spring Boot 1.5.1 .版本
  2. 专家

1.项目结构

一个标准的 Maven 项目结构。

project directory ## 2.项目依赖性

标准spring-boot-starterspring-boot-starter-test

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>spring-boot-profile</artifactId><packaging>jar</packaging><name>Spring Boot Profiles Example</name><description>Spring Boot Profiles Example</description><url>https://www.mkyong.com</url><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.4.2.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project> 

3.Spring Boot

在 Spring Boot,默认配置文件是“default”。查看以下天气服务。

3.1 一个接口。

WeatherService.java

 package com.mkyong.service;public interface WeatherService {String forecast();} 

3.2 简介:阳光默认。

SunnyDayService.java

 package com.mkyong.service;import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;@Service
@Profile({"sunny", "default"})
public class SunnyDayService implements WeatherService {@Overridepublic String forecast() {return "Today is sunny day!";}} 

3.3 简介:下雨。

RainingDayService.java

 package com.mkyong.service;import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;@Service
@Profile("raining")
public class RainingDayService implements WeatherService {@Overridepublic String forecast() {return "Today is raining day!";}} 

3.4 启动 Spring Boot 应用程序。

Application.java

 package com.mkyong;import com.mkyong.service.WeatherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Application implements CommandLineRunner {@Autowiredprivate WeatherService weatherService;@Overridepublic void run(String... args) throws Exception {//weather forecast, default is sunny day!System.out.println(weatherService.forecast());}public static void main(String[] args) throws Exception {SpringApplication.run(Application.class, args);}} 

3.5 属性文件。

application.properties

 # default profile is 'defau;t'
#spring.profiles.active=sunnylogging.level.=error
spring.main.banner-mode=off 

4.单元测试

一些单元测试的例子。

4.1 服务类的单元测试。通过@ActiveProfiles设置激活的个人信息

TestWeatherService.java

 package com.mkyong;import com.mkyong.service.WeatherService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;import static org.assertj.core.api.Assertions.assertThat;@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("raining")
public class TestWeatherService {@AutowiredWeatherService weatherService;@Testpublic void testRainingProfile() throws Exception {String output = weatherService.forecast();assertThat(output).contains("Today is raining day!");}
} 

4.2 对 Spring Boot 应用程序进行单元测试。您可以通过属性spring.profiles.active设置活动配置文件

TestApplication.java

 package com.mkyong;import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.test.rule.OutputCapture;import static org.assertj.core.api.Assertions.assertThat;public class TestApplication {@Rulepublic OutputCapture outputCapture = new OutputCapture();@Testpublic void testDefaultProfile() throws Exception {Application.main(new String[0]);String output = this.outputCapture.toString();assertThat(output).contains("Today is sunny day!");}@Testpublic void testRainingProfile() throws Exception {System.setProperty("spring.profiles.active", "raining");Application.main(new String[0]);String output = this.outputCapture.toString();assertThat(output).contains("Today is raining day!");}@Testpublic void testRainingProfile_withDoption() throws Exception {Application.main(new String[]{"--spring.profiles.active=raining"});String output = this.outputCapture.toString();assertThat(output).contains("Today is raining day!");}@Afterpublic void after() {System.clearProperty("spring.profiles.active");}} 

这个 Spring Boot 的例子值得称赞。

5.演示

打包并运行它。

 $ mvn package#default profile, sunny day!
$ java -jar target/spring-boot-profile-1.0.jar
Today is sunny day!# set a profile
$ java -jar -Dspring.profiles.active=raining target/spring-boot-profile-1.0.jar
Today is raining day! 

下载源代码

Download – spring-boot-profile-example.zip (5 KB)

参考

  1. 弹簧轮廓示例
  2. Spring Boot–属性&配置
  3. Spring Boot–简介

profiles spring boot spring profile

Spring Boot-应用程序启动时运行代码

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-run-code-when-the-application-starts/

在 Spring Boot,当应用程序完全启动时,我们可以创建一个CommandLineRunner bean 来运行代码。

StartBookApplication.java

 package com.mkyong;import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;@SpringBootApplication
public class StartBookApplication {public static void main(String[] args) {SpringApplication.run(StartBookApplication.class, args);}// Injects a repository bean@BeanCommandLineRunner initDatabase(BookRepository repository) {return args -> {repository.save(new Book("A Guide to the Bodhisattva Way of Life"));};}// Injects a ApplicationContext@BeanCommandLineRunner initPrint(ApplicationContext ctx) {return args -> {System.out.println("All beans loaded by Spring Boot:\n");List<String> beans = Arrays.stream(ctx.getBeanDefinitionNames()).sorted(Comparator.naturalOrder()).collect(Collectors.toList());beans.forEach(x -> System.out.println(x));};}// Injects nothing@BeanCommandLineRunner initPrintOneLine() {return args -> {System.out.println("Hello World Spring Boot!");};}} 

用 Spring Boot 2 号进行了测试

参考

  • 命令行运行程序

Spring Boot–显示 Hibernate SQL 查询

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-show-hibernate-sql-query/

application.properties中添加以下行来记录 Hibernate SQL 查询。

application.properties

 #show sql statement
logging.level.org.hibernate.SQL=debug#show sql values
logging.level.org.hibernate.type.descriptor.sql=trace 

1.org.hibernate.SQL=debug

application.properties

 logging.level.org.hibernate.SQL=debug 

1.1 选择查询。

Console

 2017-02-23 21:36:42 DEBUG org.hibernate.SQL - select customer0_.id as id1_0_, customer0_.created_date as created_date2_0_, customer0_.email as email3_0_, customer0_.name as name4_0_ from customer customer0_ 

2.org . hibernate . type . descriptor . SQL = trace

application.properties

 logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.type.descriptor.sql=trace 

2.1 选择查询及其值。

Console

 2017-02-23 21:39:23 DEBUG org.hibernate.SQL - select customer0_.id as id1_0_, customer0_.created_date as created_date2_0_, customer0_.email as email3_0_, customer0_.name as name4_0_ from customer customer0_2017-02-23 21:39:23 TRACE o.h.t.descriptor.sql.BasicExtractor - extracted value ([id1_0_] : [BIGINT]) - [1]
2017-02-23 21:39:23 TRACE o.h.t.descriptor.sql.BasicExtractor - extracted value ([created_date2_0_] : [TIMESTAMP]) - [2017-02-11 00:00:00.0]
2017-02-23 21:39:23 TRACE o.h.t.descriptor.sql.BasicExtractor - extracted value ([email3_0_] : [VARCHAR]) - [111@yahoo.com]
2017-02-23 21:39:23 TRACE o.h.t.descriptor.sql.BasicExtractor - extracted value ([name4_0_] : [VARCHAR]) - [mkyong]
2017-02-23 21:39:23 TRACE o.h.t.descriptor.sql.BasicExtractor - extracted value ([id1_0_] : [BIGINT]) - [2]
2017-02-23 21:39:23 TRACE o.h.t.descriptor.sql.BasicExtractor - extracted value ([created_date2_0_] : [TIMESTAMP]) - [2017-02-12 00:00:00.0]
2017-02-23 21:39:23 TRACE o.h.t.descriptor.sql.BasicExtractor - extracted value ([email3_0_] : [VARCHAR]) - [222@yahoo.com]
2017-02-23 21:39:23 TRACE o.h.t.descriptor.sql.BasicExtractor - extracted value ([name4_0_] : [VARCHAR]) - [yflow]
2017-02-23 21:39:23 TRACE o.h.t.descriptor.sql.BasicExtractor - extracted value ([id1_0_] : [BIGINT]) - [3]
2017-02-23 21:39:23 TRACE o.h.t.descriptor.sql.BasicExtractor - extracted value ([created_date2_0_] : [TIMESTAMP]) - [2017-02-13 00:00:00.0]
2017-02-23 21:39:23 TRACE o.h.t.descriptor.sql.BasicExtractor - extracted value ([email3_0_] : [VARCHAR]) - [333@yahoo.com]
2017-02-23 21:39:23 TRACE o.h.t.descriptor.sql.BasicExtractor - extracted value ([name4_0_] : [VARCHAR]) - [zilap] 

2.2 插入查询及其值。

Console

 2017-02-23 21:44:15 DEBUG org.hibernate.SQL - select customer_seq.nextval from dual
2017-02-23 21:44:15 DEBUG org.hibernate.SQL - insert into customer (created_date, email, name, id) values (?, ?, ?, ?)2017-02-23 21:44:15 TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [TIMESTAMP] - [Thu Feb 23 21:44:15 SGT 2017]
2017-02-23 21:44:15 TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [2] as [VARCHAR] - [aa]
2017-02-23 21:44:15 TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [3] as [VARCHAR] - [a]
2017-02-23 21:44:15 TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [4] as [BIGINT] - [1] 

Note
You might be interested in this article – Hibernate Logging Guide

参考

  1. Spring Boot SLF4J 测井示例

Spring Boot SLF4j 回溯示例

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-slf4j-logging-example/

spring boot slf4j logback

在本教程中,我们将向您展示如何在 Spring Boot 框架中使用 Logback 。

使用的技术:

  • Spring Boot 2.1.2 .版本
  • 弹簧 5.1.4 释放
  • 回溯 1.2.3
  • maven3
  • Java 8

1.项目目录

project directory

2.专家

在 Spring Boot,Logback 是默认的日志框架,只需添加spring-boot-starter-web,它将引入logback依赖项。

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>spring-boot-slf4j</artifactId><packaging>jar</packaging><name>Spring Boot SLF4j</name><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.22.0</version></plugin></plugins></build>
</project> 

显示项目依赖关系。

 $ mvn dependency:tree+- org.springframework.boot:spring-boot-starter-web:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.1.2.RELEASE:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.2.3:compile 
 $ mvn dependency:treeorg.springframework.boot:spring-boot-slf4j:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.1.2.RELEASE:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] |  |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.11.1:compile
[INFO] |  |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.11.1:compile
[INFO] |  |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
[INFO] |  |  +- javax.annotation:javax.annotation-api:jar:1.3.2:compile
[INFO] |  |  +- org.springframework:spring-core:jar:5.1.4.RELEASE:compile
[INFO] |  |  |  \- org.springframework:spring-jcl:jar:5.1.4.RELEASE:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.23:runtime
[INFO] |  +- org.springframework.boot:spring-boot-starter-json:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.8:compile
[INFO] |  |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile
[INFO] |  |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.9.8:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.9.8:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.9.8:compile
[INFO] |  |  \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.9.8:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.14:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:9.0.14:compile
[INFO] |  |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.14:compile
[INFO] |  +- org.hibernate.validator:hibernate-validator:jar:6.0.14.Final:compile
[INFO] |  |  +- javax.validation:validation-api:jar:2.0.1.Final:compile
[INFO] |  |  +- org.jboss.logging:jboss-logging:jar:3.3.2.Final:compile
[INFO] |  |  \- com.fasterxml:classmate:jar:1.4.0:compile
[INFO] |  +- org.springframework:spring-web:jar:5.1.4.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-beans:jar:5.1.4.RELEASE:compile
[INFO] |  \- org.springframework:spring-webmvc:jar:5.1.4.RELEASE:compile
[INFO] |     +- org.springframework:spring-aop:jar:5.1.4.RELEASE:compile
[INFO] |     +- org.springframework:spring-context:jar:5.1.4.RELEASE:compile
[INFO] |     \- org.springframework:spring-expression:jar:5.1.4.RELEASE:compile
[INFO] +- org.springframework.boot:spring-boot-starter-thymeleaf:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.thymeleaf:thymeleaf-spring5:jar:3.0.11.RELEASE:compile
[INFO] |  |  +- org.thymeleaf:thymeleaf:jar:3.0.11.RELEASE:compile
[INFO] |  |  |  +- org.attoparser:attoparser:jar:2.0.5.RELEASE:compile
[INFO] |  |  |  \- org.unbescape:unbescape:jar:1.1.6.RELEASE:compile
[INFO] |  |  \- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] |  \- org.thymeleaf.extras:thymeleaf-extras-java8time:jar:3.0.2.RELEASE:compile
[INFO] \- org.springframework.boot:spring-boot-devtools:jar:2.1.2.RELEASE:compile (optional)
[INFO]    +- org.springframework.boot:spring-boot:jar:2.1.2.RELEASE:compile
[INFO]    \- org.springframework.boot:spring-boot-autoconfigure:jar:2.1.2.RELEASE:compile 

3.应用程序.属性

3.1 在application.properties中配置记录

application.properties

 # logging level
logging.level.org.springframework=ERROR
logging.level.com.mkyong=DEBUG# output to a file
logging.file=app.log# temp folder example
#logging.file=${java.io.tmpdir}/app.loglogging.pattern.file=%d %p %c{1.} [%t] %m%nlogging.pattern.console=%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n## if no active profile, default is 'default'
##spring.profiles.active=prod# root level
#logging.level.=INFO 

3.2 这相当于 YAML 格式。

application.yml

 logging:level:org.springframework: ERRORcom.mkyong: DEBUGpattern:console: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"file: "%d %p %c{1.} [%t] %m%n"file: app.log 

4.logback.xml

上面的日志配置对于开发来说已经足够了。对于生产,我们需要更多的日志功能,如文件滚动或 SMTP。在 Spring Boot,我们仍然允许通过标准logback.xml配置回退

project directorylogback.xml

 <?xml version="1.0" encoding="UTF-8"?>
<configuration><property name="HOME_LOG" value="logs/app.log"/><appender name="FILE-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${HOME_LOG}</file><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>logs/archived/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern><!-- each archived file, size max 10MB --><maxFileSize>10MB</maxFileSize><!-- total size of all archive files, if total size > 20GB, it will delete old archived file --><totalSizeCap>20GB</totalSizeCap><!-- 60 days to keep --><maxHistory>60</maxHistory></rollingPolicy><encoder><pattern>%d %p %c{1.} [%t] %m%n</pattern></encoder></appender><logger name="com.mkyong" level="debug" additivity="false"><appender-ref ref="FILE-ROLLING"/></logger><root level="error"><appender-ref ref="FILE-ROLLING"/></root></configuration> 

5.按剖面进行 Spring Boot 测井

Note
Read this – Profile-specific configuration

为了利用 Spring Boot 提供的模板特性,我们可以在类路径的根目录下创建一个logback-spring.xml

project directory

在下面的配置中:

  • 如果没有活动的配置文件(默认),则记录到控制台。
  • 如果配置文件是prod,记录到一个滚动文件。

logback-spring.xml

 <?xml version="1.0" encoding="UTF-8"?>
<configuration><include resource="org/springframework/boot/logging/logback/defaults.xml" /><springProfile name="default"><include resource="org/springframework/boot/logging/logback/console-appender.xml"/><root level="INFO"><appender-ref ref="CONSOLE"/></root></springProfile><springProfile name="prod"><appender name="FILE-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>app.log</file><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>logs/archived/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern><!-- each archived file, size max 10MB --><maxFileSize>10MB</maxFileSize><!-- total size of all archive files, if total size > 20GB, it will delete old archived file --><totalSizeCap>20GB</totalSizeCap><!-- 60 days to keep --><maxHistory>60</maxHistory></rollingPolicy><encoder><pattern>%d %p %c{1.} [%t] %m%n</pattern></encoder></appender><logger name="org.springframework" level="INFO"/><logger name="com.mkyong" level="DEBUG"/><root level="ERROR"><appender-ref ref="FILE-ROLLING"/></root></springProfile></configuration> 

定义一个spring.profiles.active属性来设置当前活动的配置文件。

application.properties

 ## if no active profile, default is 'default'
spring.profiles.active=prod 

6.你好 Logback

6.1 一个简单的 Spring MVC web 应用程序,记录一些东西。

HelloController.java

 package com.mkyong;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;import java.util.Arrays;
import java.util.List;@Controller
public class HelloController {private static final Logger logger = LoggerFactory.getLogger(HelloController.class);@GetMapping("/")public String hello(Model model) {List<Integer> data = Arrays.asList(1, 2, 3, 4, 5);logger.debug("Hello from Logback {}", data);model.addAttribute("num", data);return "index"; // index.html}} 

6.2 模板

src/resources/templates/index.html

 <!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>Spring Boot SLF4j Logback</title><link rel="stylesheet" th:href="@{/css/main.css}" href="../../css/main.css"/>
</head>
<body><h1>Spring Boot + SLF4j Logback example</h1>
<ul><li th:each="n : ${num}" th:text="${n}"></li>
</ul></body>
</html> 

6.3 CSS

src/resources/static/css/main.css

 h1{color:#0000FF;
} 

7.演示

7.1 启动 Spring Boot

StartWebApplication.java

 package com.mkyong;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class StartWebApplication {public static void main(String[] args) {SpringApplication.run(StartWebApplication.class, args);}} 

http://localhost:8080

demoTerminal

 15:15:11.588 [http-nio-8080-exec-1] DEBUG com.mkyong.HelloController - Hello from Logback [1, 2, 3, 4, 5] 

下载源代码

$ git clone https://github.com/mkyong/spring-boot.git
$ cd logging-slf4j-logback
$ mvn spring-boot:run

访问 localhost:8080
查看控制台记录信息。

参考

  • Spring Boot 测井
  • 回溯项目
  • stack overflow–Spring Boot:我如何用 application.properties 设置日志级别?
  • SLF4J 后勤指南
  • logback.xml 示例

Spring Boot +春季数据 JPA + Java 8 日期和时间(JSR310)

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-spring-data-jpa-java-8-date-and-time-jsr310/

在 Spring Boot + Spring Data JPA 应用程序中,为了支持 JSR 310java.time.*API,我们需要手动注册这个Jsr310JpaConverters

 import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters;@EntityScan(basePackageClasses = {Application.class, Jsr310JpaConverters.class}
)
@SpringBootApplication
public class Application {//...
} 

用 Spring Boot 1.5.1 .版本测试的 PS,Spring Data JPA 1.11.0 .版本

1.完整示例

1.1 一个模型包含一个java.time.LocalDate字段。

 package com.mkyong.model;import javax.persistence.*;
import java.time.LocalDate;@Entity
public class Customer {@Id@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUST_SEQ")@SequenceGenerator(sequenceName = "customer_seq", allocationSize = 1, name = "CUST_SEQ")Long id;String name;@Column(name = "CREATED_DATE")LocalDate date;//... 

1.2 @EntityScan扫描并记录Jsr310JpaConverters如下:

 package com.mkyong;import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters;import java.util.Arrays;//for jsr310 java 8 java.time.*
@EntityScan(basePackageClasses = {Application.class, Jsr310JpaConverters.class}
)
@SpringBootApplication
public class Application {public static void main(String[] args) throws Exception {SpringApplication.run(Application.class, args);}@Beanpublic CommandLineRunner run(ApplicationContext appContext) {return args -> {System.out.println("hello World!");};}} 

参考

  1. JSR 310 JPA converters JavaDoc
  2. JSR 310:日期和时间 API
  3. Spring Data MongoDB + JSR-310 或 Java 8 新日期 API

Spring Boot +春天数据 JPA + MySQL

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-spring-data-jpa-mysql-example/

spring boot spring data jpa mysql

之前的 Spring Boot + Spring 数据 JPA 将被重用,修改为支持 MySQL 数据库。

使用的技术:

  • Spring Boot 2.1.2 .版本
  • 弹簧 5.1.4 释放
  • 休眠 5.3.7
  • HikariCP 3.2.0
  • MySQL-连接器-java:jar 8.0.13
  • maven3
  • Java 8

1.专家

为了连接一个 MySQL,声明mysql-connector-java

pom.xml

 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency> 

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>spring-boot-data-jpa</artifactId><packaging>jar</packaging><name>Spring Boot Spring Data JPA</name><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version></parent><properties><java.version>1.8</java.version><downloadSources>true</downloadSources><downloadJavadocs>true</downloadJavadocs></properties><dependencies><!-- jpa, crud repository --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- MySQL --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.22.0</version></plugin></plugins></build>
</project> 

2.配置 MySQL

2.1 更新spring.datasource.*中的 MySQL 设置

application.properties

 ## MySQL
spring.datasource.url=jdbc:mysql://localhost:3306/wordpress
spring.datasource.username=mkyong
spring.datasource.password=password#`hibernate_sequence' doesn't exist
spring.jpa.hibernate.use-new-id-generator-mappings=false# drop n create table, good for testing, comment this in production
spring.jpa.hibernate.ddl-auto=create 

完成了。

下载源代码

$ git clone https://github.com/mkyong/spring-boot.git
$ cd spring-data-jpa-mysql
$ mvn spring-boot:run

参考

  • 鼠标指针
  • 春季数据 JPA 文档
  • 使用 SQL 数据库
  • 常用应用属性
  • 使用 MySQL 访问数据

Spring Boot +春季数据 JPA + Oracle 示例

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-spring-data-jpa-oracle-example/

在本文中,我们将向您展示如何创建一个 Spring Boot+Spring Data JPA+Oracle+hikari CP 连接池示例。

本文中使用的工具:

  1. Spring Boot 1.5.1 .版本
  2. 春季数据 1.13.0 .发布
  3. 休眠 5
  4. Oracle 数据库 11g 快速版
  5. Oracle JDBC 驱动程序 ojdbc7.jar
  6. HikariCP 2.6
  7. 专家
  8. Java 8

1.项目结构

一个标准的 Maven 项目结构。

2.项目依赖性

声明spring-boot-starter-data-jpa,它抓取 Spring 数据,Hibernate 和 JPA 相关的东西。

pom.xml

 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mkyong</groupId><artifactId>spring-boot-jpa-oracle-example</artifactId><packaging>jar</packaging><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.1.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- Spring data JPA, default tomcat pool, exclude it --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId><exclusions><exclusion><groupId>org.apache.tomcat</groupId><artifactId>tomcat-jdbc</artifactId></exclusion></exclusions></dependency><!-- Oracle JDBC driver --><dependency><groupId>com.oracle</groupId><artifactId>ojdbc7</artifactId><version>12.1.0</version></dependency><!-- HikariCP connection pool --><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>2.6.0</version></dependency></dependencies><build><plugins><!-- Package as an executable jar/war --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project> 

详细检查项目依赖关系。

Terminal

 $ mvn dependency:tree
[INFO] ------------------------------------------------------------------------
[INFO] Building spring-boot-jpa-oracle-example 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.10:tree (default-cli) @ spring-boot-jpa-oracle-example ---
[INFO] com.mkyong:spring-boot-jpa-oracle-example:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter:jar:1.5.1.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot:jar:1.5.1.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-context:jar:4.3.6.RELEASE:compile
[INFO] |  |     \- org.springframework:spring-expression:jar:4.3.6.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-autoconfigure:jar:1.5.1.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-logging:jar:1.5.1.RELEASE:compile
[INFO] |  |  +- ch.qos.logback:logback-classic:jar:1.1.9:compile
[INFO] |  |  |  \- ch.qos.logback:logback-core:jar:1.1.9:compile
[INFO] |  |  +- org.slf4j:jcl-over-slf4j:jar:1.7.22:compile
[INFO] |  |  +- org.slf4j:jul-to-slf4j:jar:1.7.22:compile
[INFO] |  |  \- org.slf4j:log4j-over-slf4j:jar:1.7.22:compile
[INFO] |  +- org.springframework:spring-core:jar:4.3.6.RELEASE:compile
[INFO] |  \- org.yaml:snakeyaml:jar:1.17:runtime
[INFO] +- org.springframework.boot:spring-boot-starter-data-jpa:jar:1.5.1.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-aop:jar:1.5.1.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-aop:jar:4.3.6.RELEASE:compile
[INFO] |  |  \- org.aspectj:aspectjweaver:jar:1.8.9:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-jdbc:jar:1.5.1.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-jdbc:jar:4.3.6.RELEASE:compile
[INFO] |  +- org.hibernate:hibernate-core:jar:5.0.11.Final:compile
[INFO] |  |  +- org.jboss.logging:jboss-logging:jar:3.3.0.Final:compile
[INFO] |  |  +- org.hibernate.javax.persistence:hibernate-jpa-2.1-api:jar:1.0.0.Final:compile
[INFO] |  |  +- org.javassist:javassist:jar:3.21.0-GA:compile
[INFO] |  |  +- antlr:antlr:jar:2.7.7:compile
[INFO] |  |  +- org.jboss:jandex:jar:2.0.0.Final:compile
[INFO] |  |  +- dom4j:dom4j:jar:1.6.1:compile
[INFO] |  |  \- org.hibernate.common:hibernate-commons-annotations:jar:5.0.1.Final:compile
[INFO] |  +- org.hibernate:hibernate-entitymanager:jar:5.0.11.Final:compile
[INFO] |  +- javax.transaction:javax.transaction-api:jar:1.2:compile
[INFO] |  +- org.springframework.data:spring-data-jpa:jar:1.11.0.RELEASE:compile
[INFO] |  |  +- org.springframework.data:spring-data-commons:jar:1.13.0.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-orm:jar:4.3.6.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-tx:jar:4.3.6.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-beans:jar:4.3.6.RELEASE:compile
[INFO] |  \- org.springframework:spring-aspects:jar:4.3.6.RELEASE:compile
[INFO] +- com.oracle:ojdbc7:jar:12.1.0:compile
[INFO] \- com.zaxxer:HikariCP:jar:2.6.0:compile
[INFO]    \- org.slf4j:slf4j-api:jar:1.7.22:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------ 

Note
Read this – Maven Install Oracle JDBC driver

3.Java 持久性 API–JPA

3.1 客户模型。添加 JPA 注释,并使用“sequence”来生成自动增加的主 ID。

Customer.java

 package com.mkyong.model;import javax.persistence.*;
import java.util.Date;@Entity
public class Customer {// "customer_seq" is Oracle sequence name.@Id@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUST_SEQ")@SequenceGenerator(sequenceName = "customer_seq", allocationSize = 1, name = "CUST_SEQ")Long id;String name;String email;@Column(name = "CREATED_DATE")Date date;//getters and setters, contructors
} 

4.配置+数据库初始化

4.1 配置 Oracle 数据源、HikariCP 设置并显示 Hibernate 查询。

application.properties

 spring.main.banner-mode=off# create and drop tables and sequences, loads import.sql
spring.jpa.hibernate.ddl-auto=create-drop# Oracle settings
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=system
spring.datasource.password=password
spring.datasource.driver-class-oracle.jdbc.driver.OracleDriver# HikariCP settings
# spring.datasource.hikari.*spring.datasource.hikari.connection-timeout=60000
spring.datasource.hikari.maximum-pool-size=5# logging
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
logging.level.org.hibernate.SQL=debug
#logging.level.org.hibernate.type.descriptor.sql=trace
logging.level.=error 

4.2 如果在类路径中找到了import.sql,Hibernate 会自动加载。

import.sql

 INSERT INTO "CUSTOMER" (ID, NAME, EMAIL, CREATED_DATE) VALUES(1, 'mkyong','111@yahoo.com', TO_DATE('2017-02-11', 'yyyy-mm-dd'));
INSERT INTO "CUSTOMER" (ID, NAME, EMAIL, CREATED_DATE) VALUES(2, 'yflow','222@yahoo.com', TO_DATE('2017-02-12', 'yyyy-mm-dd'));
INSERT INTO "CUSTOMER" (ID, NAME, EMAIL, CREATED_DATE) VALUES(3, 'zilap','333@yahoo.com', TO_DATE('2017-02-13', 'yyyy-mm-dd')); 

Note
Read this – Spring Database initialization

5.@仓库

5.1 创建接口并扩展 Spring 数据CrudRepository

CustomerRepository.java

 package com.mkyong.dao;import com.mkyong.model.Customer;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;import java.util.Date;
import java.util.List;
import java.util.stream.Stream;public interface CustomerRepository extends CrudRepository<Customer, Long> {List<Customer> findByEmail(String email);List<Customer> findByDate(Date date);// custom query example and return a stream@Query("select c from Customer c where c.email = :email")Stream<Customer> findByEmailReturnStream(@Param("email") String email);} 

Note
No need implementation, Spring data will create the common implementation by field name, like findByfieldName (). Read this working with Spring Data Repositories

6.Spring Boot 起动器

Application.java

 package com.mkyong;import com.mkyong.dao.CustomerRepository;
import com.mkyong.model.Customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.Transactional;import javax.sql.DataSource;
import java.text.SimpleDateFormat;
import java.util.stream.Stream;import static java.lang.System.exit;@SpringBootApplication
public class Application implements CommandLineRunner {private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");@AutowiredDataSource dataSource;@AutowiredCustomerRepository customerRepository;public static void main(String[] args) throws Exception {SpringApplication.run(Application.class, args);}@Transactional(readOnly = true)@Overridepublic void run(String... args) throws Exception {System.out.println("DATASOURCE = " + dataSource);System.out.println("\n1.findAll()...");for (Customer customer : customerRepository.findAll()) {System.out.println(customer);}System.out.println("\n2.findByEmail(String email)...");for (Customer customer : customerRepository.findByEmail("222@yahoo.com")) {System.out.println(customer);}System.out.println("\n3.findByDate(Date date)...");for (Customer customer : customerRepository.findByDate(sdf.parse("2017-02-12"))) {System.out.println(customer);}// For Stream, need @TransactionalSystem.out.println("\n4.findByEmailReturnStream(@Param(\"email\") String email)...");try (Stream<Customer> stream = customerRepository.findByEmailReturnStream("333@yahoo.com")) {stream.forEach(x -> System.out.println(x));}System.out.println("Done!");exit(0);}} 

8.演示

运行它,阅读控制台不言自明。

Terminal

 2017-02-22 12:36:49 DEBUG org.hibernate.SQL - drop table customer cascade constraints
2017-02-22 12:36:49 ERROR o.h.tool.hbm2ddl.SchemaExport - HHH000389: Unsuccessful: drop table customer cascade constraints
2017-02-22 12:36:49 ERROR o.h.tool.hbm2ddl.SchemaExport - ORA-00942: table or view does not exist2017-02-22 12:36:49 DEBUG org.hibernate.SQL - drop sequence customer_seq
2017-02-22 12:36:49 ERROR o.h.tool.hbm2ddl.SchemaExport - HHH000389: Unsuccessful: drop sequence customer_seq
2017-02-22 12:36:49 ERROR o.h.tool.hbm2ddl.SchemaExport - ORA-02289: sequence does not exist2017-02-22 12:36:49 DEBUG org.hibernate.SQL - create sequence customer_seq start with 1 increment by 1
2017-02-22 12:36:49 DEBUG org.hibernate.SQL - create table customer (id number(19,0) not null, created_date timestamp, email varchar2(255 char), name varchar2(255 char), primary key (id))
DATASOURCE = HikariDataSource (HikariPool-1)1.findAll()...
2017-02-22 12:36:50 DEBUG org.hibernate.SQL - select customer0_.id as id1_0_, customer0_.created_date as created_date2_0_, customer0_.email as email3_0_, customer0_.name as name4_0_ from customer customer0_
Customer{id=1, name='mkyong', email='111@yahoo.com', date=2017-02-11 00:00:00.0}
Customer{id=2, name='yflow', email='222@yahoo.com', date=2017-02-12 00:00:00.0}
Customer{id=3, name='zilap', email='333@yahoo.com', date=2017-02-13 00:00:00.0}2.findByEmail(String email)...
2017-02-22 12:36:50 DEBUG org.hibernate.SQL - select customer0_.id as id1_0_, customer0_.created_date as created_date2_0_, customer0_.email as email3_0_, customer0_.name as name4_0_ from customer customer0_ where customer0_.email=?
Customer{id=2, name='yflow', email='222@yahoo.com', date=2017-02-12 00:00:00.0}3.findByDate(Date date)...
2017-02-22 12:36:50 DEBUG org.hibernate.SQL - select customer0_.id as id1_0_, customer0_.created_date as created_date2_0_, customer0_.email as email3_0_, customer0_.name as name4_0_ from customer customer0_ where customer0_.created_date=?
Customer{id=2, name='yflow', email='222@yahoo.com', date=2017-02-12 00:00:00.0}4.findByEmailReturnStream(@Param("email") String email)...
2017-02-22 12:36:50 DEBUG org.hibernate.SQL - select customer0_.id as id1_0_, customer0_.created_date as created_date2_0_, customer0_.email as email3_0_, customer0_.name as name4_0_ from customer customer0_ where customer0_.email=?
Customer{id=3, name='zilap', email='333@yahoo.com', date=2017-02-13 00:00:00.0}
Done!
2017-02-22 12:36:50 DEBUG org.hibernate.SQL - drop table customer cascade constraints
2017-02-22 12:36:50 DEBUG org.hibernate.SQL - drop sequence customer_seqProcess finished with exit code 0 

下载源代码

Download – spring-boot-jpa-oracle-example.zip (6 KB)

参考

  1. Maven 安装甲骨文 JDBC 驱动
  2. 使用 JPA 初始化数据库
  3. 弹簧靴 ddl 自动发电机
  4. Spring 数据共享——参考文档
  5. 使用 JPA 访问数据
  6. TopLink JPA:如何配置主键生成
  7. Oracle / PLSQL:序列(自动编号)
  8. Spring Boot JDBC + Oracle 数据库+ Commons DBCP2 示例

Spring Boot +春季数据 JPA + PostgreSQL

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-spring-data-jpa-postgresql/

spring boot spring data jpa postgresql

之前的 Spring Boot + Spring 数据 JPA 将被重用,修改后支持 PostgreSQL 数据库。

使用的技术:

  • Spring Boot 2.1.2 .版本
  • 弹簧 5.1.4 释放
  • 休眠 5.3.7
  • HikariCP 3.2.0
  • PostgreSQL 驱动程序 42.2.5
  • maven3
  • Java 8

放置一个postgresql驱动程序,并在application.properties中定义数据源 url。完成后,Spring Boot 就可以连接到 PostgreSQL 数据库了。

pom.xml

 <dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId></dependency> 

1.专家

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>spring-boot-data-jpa</artifactId><packaging>jar</packaging><name>Spring Boot Spring Data JPA</name><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version></parent><properties><java.version>1.8</java.version><downloadSources>true</downloadSources><downloadJavadocs>true</downloadJavadocs></properties><dependencies><!-- jpa, crud repository --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- PostgreSQL --><dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.22.0</version></plugin></plugins></build>
</project> 

2.配置 PostgreSQL

2.1 更新spring.datasource.*中的 PostgreSQL 设置

application.properties

 ## default connection pool
spring.datasource.hikari.connectionTimeout=20000
spring.datasource.hikari.maximumPoolSize=5## PostgreSQL
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=password#drop n create table again, good for testing, comment this in production
spring.jpa.hibernate.ddl-auto=create 

完成了。

下载源代码

$ git clone https://github.com/mkyong/spring-boot.git
$ cd spring-data-jpa-postgresql
$ mvn spring-boot:run

参考

  • PostgreSQL
  • 鼠标指针
  • 春季数据 JPA 文档
  • 使用 SQL 数据库
  • 常用应用属性
  • Spring Boot +春季数据 JPA

Spring Boot +春季数据 JPA

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-spring-data-jpa/

spring boot spring data jpa

在本教程中,我们将向您展示如何使用 Spring Boot + Spring data JPA 将数据保存到 H2 内存数据库中,以及如何查询数据。

使用的技术:

  • Spring Boot 2.1.2 .版本
  • 弹簧 5.1.4 释放
  • 休眠 5.3.7
  • HikariCP 3.2.0
  • H2 内存数据库 1.4.197
  • maven3
  • Java 8

Note
By default, Spring Boot 2 uses HikariCP as the database connection pool. Read this Spring Boot algorithm to choose a pool implementation.

1.项目目录

project directory

2.专家

放置spring-boot-starter-data-jpa,它将获得 Spring 数据、Hibernate、HikariCP 和所有数据库相关的依赖项。

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>spring-data-jpa</artifactId><packaging>jar</packaging><name>Spring Boot Spring Data JPA</name><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version></parent><properties><java.version>1.8</java.version><downloadSources>true</downloadSources><downloadJavadocs>true</downloadJavadocs></properties><dependencies><!-- jpa, crud repository --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- in-memory database  --><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.22.0</version></plugin></plugins></build>
</project> 

显示项目依赖关系。

 $ mvn dependency:tree[INFO] org.springframework.boot:spring-boot-data-jpa:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-data-jpa:jar:2.1.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-aop:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-aop:jar:5.1.4.RELEASE:compile
[INFO] |  |  \- org.aspectj:aspectjweaver:jar:1.9.2:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-jdbc:jar:2.1.2.RELEASE:compile
[INFO] |  |  +- com.zaxxer:HikariCP:jar:3.2.0:compile
[INFO] |  |  \- org.springframework:spring-jdbc:jar:5.1.4.RELEASE:compile
[INFO] |  +- javax.transaction:javax.transaction-api:jar:1.3:compile
[INFO] |  +- javax.xml.bind:jaxb-api:jar:2.3.1:compile
[INFO] |  |  \- javax.activation:javax.activation-api:jar:1.2.0:compile
[INFO] |  +- org.hibernate:hibernate-core:jar:5.3.7.Final:compile
[INFO] |  |  +- org.jboss.logging:jboss-logging:jar:3.3.2.Final:compile
[INFO] |  |  +- javax.persistence:javax.persistence-api:jar:2.2:compile
[INFO] |  |  +- org.javassist:javassist:jar:3.23.1-GA:compile
[INFO] |  |  +- net.bytebuddy:byte-buddy:jar:1.9.7:compile
[INFO] |  |  +- antlr:antlr:jar:2.7.7:compile
[INFO] |  |  +- org.jboss:jandex:jar:2.0.5.Final:compile
[INFO] |  |  +- com.fasterxml:classmate:jar:1.4.0:compile
[INFO] |  |  +- org.dom4j:dom4j:jar:2.1.1:compile
[INFO] |  |  \- org.hibernate.common:hibernate-commons-annotations:jar:5.0.4.Final:compile
[INFO] |  +- org.springframework.data:spring-data-jpa:jar:2.1.4.RELEASE:compile
[INFO] |  |  +- org.springframework.data:spring-data-commons:jar:2.1.4.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-orm:jar:5.1.4.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-context:jar:5.1.4.RELEASE:compile
[INFO] |  |  |  \- org.springframework:spring-expression:jar:5.1.4.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-tx:jar:5.1.4.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-beans:jar:5.1.4.RELEASE:compile
[INFO] |  |  \- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] |  \- org.springframework:spring-aspects:jar:5.1.4.RELEASE:compile
[INFO] +- com.h2database:h2:jar:1.4.197:compile
[INFO] \- org.springframework.boot:spring-boot-starter-test:jar:2.1.2.RELEASE:test
[INFO]    +- org.springframework.boot:spring-boot-starter:jar:2.1.2.RELEASE:compile
[INFO]    |  +- org.springframework.boot:spring-boot:jar:2.1.2.RELEASE:compile
[INFO]    |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.1.2.RELEASE:compile
[INFO]    |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.1.2.RELEASE:compile
[INFO]    |  |  +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO]    |  |  |  \- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO]    |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.11.1:compile
[INFO]    |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.11.1:compile
[INFO]    |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
[INFO]    |  +- javax.annotation:javax.annotation-api:jar:1.3.2:compile
[INFO]    |  \- org.yaml:snakeyaml:jar:1.23:runtime
[INFO]    +- org.springframework.boot:spring-boot-test:jar:2.1.2.RELEASE:test
[INFO]    +- org.springframework.boot:spring-boot-test-autoconfigure:jar:2.1.2.RELEASE:test
[INFO]    +- com.jayway.jsonpath:json-path:jar:2.4.0:test
[INFO]    |  \- net.minidev:json-smart:jar:2.3:test
[INFO]    |     \- net.minidev:accessors-smart:jar:1.2:test
[INFO]    |        \- org.ow2.asm:asm:jar:5.0.4:test
[INFO]    +- junit:junit:jar:4.12:test
[INFO]    +- org.assertj:assertj-core:jar:3.11.1:test
[INFO]    +- org.mockito:mockito-core:jar:2.23.4:test
[INFO]    |  +- net.bytebuddy:byte-buddy-agent:jar:1.9.7:test
[INFO]    |  \- org.objenesis:objenesis:jar:2.6:test
[INFO]    +- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO]    +- org.hamcrest:hamcrest-library:jar:1.3:test
[INFO]    +- org.skyscreamer:jsonassert:jar:1.5.0:test
[INFO]    |  \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test
[INFO]    +- org.springframework:spring-core:jar:5.1.4.RELEASE:compile
[INFO]    |  \- org.springframework:spring-jcl:jar:5.1.4.RELEASE:compile
[INFO]    +- org.springframework:spring-test:jar:5.1.4.RELEASE:test
[INFO]    \- org.xmlunit:xmlunit-core:jar:2.6.2:test 

3.春季数据 JPA

Book.java

 package com.mkyong;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;@Entity
public class Book {@Id@GeneratedValue(strategy = GenerationType.AUTO)private Long id;private String name;public Book() {}public Book(String name) {this.name = name;}//getters, setters, toString...
} 

BookRepository.java

 package com.mkyong;import org.springframework.data.repository.CrudRepository;import java.util.List;public interface BookRepository extends CrudRepository<Book, Long> {List<Book> findByName(String name);} 

4.@SpringBootApplication

4.1 启动 Spring Boot,将 3 本书插入 H2 数据库,并测试find()方法。

StartApplication.java

 package com.mkyong;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class StartApplication implements CommandLineRunner {private static final Logger log = LoggerFactory.getLogger(StartApplication.class);@Autowiredprivate BookRepository repository;public static void main(String[] args) {SpringApplication.run(StartApplication.class, args);}@Overridepublic void run(String... args) {log.info("StartApplication...");repository.save(new Book("Java"));repository.save(new Book("Node"));repository.save(new Book("Python"));System.out.println("\nfindAll()");repository.findAll().forEach(x -> System.out.println(x));System.out.println("\nfindById(1L)");repository.findById(1l).ifPresent(x -> System.out.println(x));System.out.println("\nfindByName('Node')");repository.findByName("Node").forEach(x -> System.out.println(x));}} 

5.HikariCP 连接池

默认情况下,Spring Boot 2 使用 HikariCP 作为默认连接池。

5.1 启用com.zaxxer的日志级别进行调试,它将打印出默认的 HikariCP 配置。

application.properties

 logging.level.org.springframework=INFO
logging.level.com.mkyong=INFO
logging.level.com.zaxxer=DEBUG
logging.level.root=ERROR 

5.2 运行 Spring Boot,检查测井记录:

 DEBUG com.zaxxer.hikari.HikariConfig - Driver class org.h2.Driver found in Thread context class loader jdk.internal.loader.ClassLoaders$AppClassLoader@28c97a5
DEBUG com.zaxxer.hikari.HikariConfig - HikariPool-1 - configuration:
DEBUG com.zaxxer.hikari.HikariConfig - allowPoolSuspension.............false
DEBUG com.zaxxer.hikari.HikariConfig - autoCommit......................true
DEBUG com.zaxxer.hikari.HikariConfig - catalog.........................none
DEBUG com.zaxxer.hikari.HikariConfig - connectionInitSql...............none
DEBUG com.zaxxer.hikari.HikariConfig - connectionTestQuery.............none
DEBUG com.zaxxer.hikari.HikariConfig - connectionTimeout...............30000
DEBUG com.zaxxer.hikari.HikariConfig - dataSource......................none
DEBUG com.zaxxer.hikari.HikariConfig - dataSourceClassName.............none
DEBUG com.zaxxer.hikari.HikariConfig - dataSourceJNDI..................none
DEBUG com.zaxxer.hikari.HikariConfig - dataSourceProperties............{password=<masked>}
DEBUG com.zaxxer.hikari.HikariConfig - driverClassName................."org.h2.Driver"
DEBUG com.zaxxer.hikari.HikariConfig - healthCheckProperties...........{}
DEBUG com.zaxxer.hikari.HikariConfig - healthCheckRegistry.............none
DEBUG com.zaxxer.hikari.HikariConfig - idleTimeout.....................600000
DEBUG com.zaxxer.hikari.HikariConfig - initializationFailTimeout.......1
DEBUG com.zaxxer.hikari.HikariConfig - isolateInternalQueries..........false
DEBUG com.zaxxer.hikari.HikariConfig - jdbcUrl.........................jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
DEBUG com.zaxxer.hikari.HikariConfig - leakDetectionThreshold..........0
DEBUG com.zaxxer.hikari.HikariConfig - maxLifetime.....................1800000
DEBUG com.zaxxer.hikari.HikariConfig - maximumPoolSize.................10
DEBUG com.zaxxer.hikari.HikariConfig - metricRegistry..................none
DEBUG com.zaxxer.hikari.HikariConfig - metricsTrackerFactory...........none
DEBUG com.zaxxer.hikari.HikariConfig - minimumIdle.....................10
DEBUG com.zaxxer.hikari.HikariConfig - password........................<masked>
DEBUG com.zaxxer.hikari.HikariConfig - poolName........................"HikariPool-1"
DEBUG com.zaxxer.hikari.HikariConfig - readOnly........................false
DEBUG com.zaxxer.hikari.HikariConfig - registerMbeans..................false
DEBUG com.zaxxer.hikari.HikariConfig - scheduledExecutor...............none
DEBUG com.zaxxer.hikari.HikariConfig - schema..........................none
DEBUG com.zaxxer.hikari.HikariConfig - threadFactory...................internal
DEBUG com.zaxxer.hikari.HikariConfig - transactionIsolation............default
DEBUG com.zaxxer.hikari.HikariConfig - username........................"sa"
DEBUG com.zaxxer.hikari.HikariConfig - validationTimeout...............5000
INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:testdb user=SA
INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Pool stats (total=1, active=0, idle=1, waiting=0)
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection conn1: url=jdbc:h2:mem:testdb user=SA
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection conn2: url=jdbc:h2:mem:testdb user=SA
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection conn3: url=jdbc:h2:mem:testdb user=SA
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection conn4: url=jdbc:h2:mem:testdb user=SA
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection conn5: url=jdbc:h2:mem:testdb user=SA
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection conn6: url=jdbc:h2:mem:testdb user=SA
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection conn7: url=jdbc:h2:mem:testdb user=SA
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection conn8: url=jdbc:h2:mem:testdb user=SA
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection conn9: url=jdbc:h2:mem:testdb user=SA
DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - After adding stats (total=10, active=0, idle=10, waiting=0) 

5.2 我们可以使用spring.datasource.hikari.*来覆盖默认设置。

application.properties

 logging.level.org.springframework=INFO
logging.level.com.mkyong=INFO
logging.level.com.zaxxer=DEBUG
logging.level.root=ERRORspring.datasource.hikari.connectionTimeout=20000
spring.datasource.hikari.maximumPoolSize=5
spring.datasource.hikari.poolName=HikariPoolZZZ 

6.单元测试

6.1 @DataJpaTestTestEntityManager测试 Spring 数据 JPA 存储库。

BookRepositoryTest.java

 package com.mkyong;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.junit4.SpringRunner;import java.util.List;import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;@RunWith(SpringRunner.class)
@DataJpaTest
public class BookRepositoryTest {@Autowiredprivate TestEntityManager entityManager;@Autowiredprivate BookRepository repository;@Testpublic void testFindByName() {entityManager.persist(new Book("C++"));List<Book> books = repository.findByName("C++");assertEquals(1, books.size());assertThat(books).extracting(Book::getName).containsOnly("C++");}} 

7.演示

 $ mvn spring-boot:runINFO  com.mkyong.StartApplication - Started StartApplication in 2.79 seconds (JVM running for 10.883)
INFO  com.mkyong.StartApplication - StartApplication...findAll()
DEBUG com.zaxxer.hikari.pool.PoolBase - HikariPoolZZZ - Reset (readOnly) on connection conn0: url=jdbc:h2:mem:testdb user=SA
Book{id=1, name='Java'}
Book{id=2, name='Node'}
Book{id=3, name='Python'}findById(1L)
DEBUG com.zaxxer.hikari.pool.PoolBase - HikariPoolZZZ - Reset (readOnly) on connection conn0: url=jdbc:h2:mem:testdb user=SA
Book{id=1, name='Java'}findByName('Node')
Book{id=2, name='Node'} 

下载源代码

$ git clone https://github.com/mkyong/spring-boot.git
$ cd spring-data-jpa
$ mvn spring-boot:run

参考

  • 鼠标指针
  • 春季数据 JPA 文档
  • 使用 SQL 数据库
  • 常用应用属性
  • JUnit–如何测试列表
  • DataJpaTest 多克
  • TestEntityManager 文档
  • Spring Boot+Spring Data JPA+Oracle 示例
  • Spring Boot 通过 JPA 访问数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/825296.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mkyong-中文博客翻译-八-

Mkyong 中文博客翻译(八)原文:Mkyong 协议:CC BY-NC-SA 4.0Spring Boot + Spring 数据 MongoDB 示例原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-spring-data-mongodb-example/在本文中,我们将向您展示如何使用 Gradle …

TortoiseSVN 下载与安装、汉化

TortoiseSVN 是 Subversion 版本控制系统的一个免费开源客户端,可以超越时间的管理文件和目录。文件保存在中央版本库,除了能记住文件和目录的每次修改以外,版本库非常像普通的文件服务器。你可以将文件恢复到过去的版本,并且可以通过检查历史知道数据做了哪些修改,谁做的…

给网站添加春节灯笼效果:引入即用,附源码!

本文介绍了一种自定义春节灯笼效果的实现方法,通过引入JavaScript代码和CSS样式,用户可以轻松地在网页中添加带有自定义文字的灯笼。相比直接使用现成的API,本文提供的代码支持手机端自适应,并允许用户修改灯笼上的文字内容。记得之前在别的网站上看到这个喜庆的春节灯笼效…

2024.10.31 文件管理方案

2024.10.31 文件管理方案文件管理方案 (注意: 红色文字为应用程序软件的名称)金山文档请在使用微信扫码登录的金山文档中新建或导入需要长时间大量编辑、长期记录或者分享给他人和他人一起查看/编辑的文档或表格。WPS文档表格打开文件密码和7-ZIP解压缩密码可以使用第37号超级…

离岗检测视频分析网关AI智能分析在岗离岗检测算法的原理与应用

在岗离岗检测算法是一项利用计算机视觉和深度学习技术的应用,它通过解析监控视频流来辨认和追踪人员,进而确定他们是否处于特定的工作区域内。算法网关视频分析网关在众多领域中都有着重要的应用价值,特别是在那些需要确认员工在岗状态的场景中,例如在工厂、仓库、银行、医…

项目实战:Qt+OpenCV仿射变换工具v1.1.0(支持打开图片、输出棋盘角点、调整偏移点、导出变换后的图等等)

需求1.打开图片;  2.矫正识别角点;  3.opencv摄像头操作子线程处理;  4.支持设置棋盘格的行列角点数; 背景深入研究图像拼接细分支算法,产出的效果查看工具,验证算法单步思路。 相关博客《项目实战:Qt+Opencv相机标定工具v1.3.0(支持打开摄像头、视频文件和网络地…

项目实战:Qt+OpenCV仿射变换工具v1.1.0(支持打开图片、输出棋盘角点、调整偏移点、导出变换后的图等等)  《项目实战:Qt+Opencv相机标定工具v1.3.0(支持打开摄像头、视频文件和

需求1.打开图片;  2.矫正识别角点;  3.opencv摄像头操作子线程处理;  4.支持设置棋盘格的行列角点数; 背景深入研究图像拼接细分支算法,产出的效果查看工具,验证算法单步思路。 相关博客《项目实战:Qt+Opencv相机标定工具v1.3.0(支持打开摄像头、视频文件和网络地…

软件开发中,做产品与做项目有什么区别

产品开发和项目开发的区别主要体现在:1.目标不同;2.开发过程不同;3.涉及人员不同;4.时间周期不同;5.结果测评不同。总的来说,产品开发更多侧重于满足市场需求和用户体验,长期维护并进行持续优化;而项目开发更注重完成特定的任务,达到预定的目标。1.目标不同 产品开发的…

SSHD服务

1.sshd服务 1.0 故障案例:openssh删除了本地连接物理服务器 ,通过远程控制卡连接.本地连接云: 登录web页面,连接.解决连接后安装openssh,软件包,直接apt/yum安装预防删除之前准备好备用方案.Telnet1.1 目标 1.修改sshd服务端配置文件修改ssh端口号,修改ssh禁用root远程登录. 2.…

BFS(Breath First Search 广度优先搜索)

BFS(Breath First Search 广度优先搜索)@目录一、知识及框架二、案例说明案例1:使用bfs计算二叉树的最小高度案例2:解开密码锁的最少次数,要求:请写一个算法,初始状态为0000,拨出target的最少次数,其中避免出现deadends中的包含的任意一个死亡密码,如果永远无法拨出tar…

MySQL安装-CentOS系统

MySQL安装-CentOS系统本文在此只介绍一种安装方式,是rpm并非yum。如果需要yum的安装方式,可以查阅其他相关资料 1.去官网下载对应的安装包 官方网站:https://www.mysql.com/,找到下载DOWNLOADS,下载操作系统对应的社区版本。本文使用的数据库版本是5.7.41在社区版本下载界…

洛谷题单指南-字符串-P3369 【模板】普通平衡树

原题链接:https://www.luogu.com.cn/problem/P3369 题意解读:平衡树的基本操作,模版题。 解题思路: 1、二叉搜索树-BST 二叉搜索树满足这样的性质:每一个节点的权值大于它的左儿子,小于它的右儿子。 对BST进行中序遍历,将得到一个从小到大的有序序列,因此BST是为了维护…