Mkyong 中文博客翻译(八)
原文:Mkyong
协议:CC BY-NC-SA 4.0
Spring Boot + Spring 数据 MongoDB 示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-spring-data-mongodb-example/
在本文中,我们将向您展示如何使用 Gradle 构建工具创建一个 Spring Boot + Spring 数据 MongoDB 应用程序。
- Spring Boot 1.5.1 .版本
- MongoDB
- Gradle
- Java 8
1.项目结构
标准项目结构。
## 2.项目依赖性
2.1 一个 Gradle 构建文件。
build.gradle
buildscript {repositories {mavenCentral()}dependencies {classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.1.RELEASE")}
}apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'jar {baseName = 'spring-data-mongodb-example'version = '1.0'
}repositories {mavenCentral()
}sourceCompatibility = 1.8
targetCompatibility = 1.8dependencies {compile 'org.springframework.boot:spring-boot-starter-data-mongodb'
}
2.2 声明了一个spring-boot-starter-data-mongodb
,它抓取了大量的库,查看以下依赖项:
Console
$ gradle dependencies --configuration runtime
:dependencies------------------------------------------------------------
Root project
------------------------------------------------------------runtime - Runtime classpath for source set 'main'.
\--- org.springframework.boot:spring-boot-starter-data-mongodb: -> 1.5.1.RELEASE+--- org.springframework.boot:spring-boot-starter:1.5.1.RELEASE| +--- org.springframework.boot:spring-boot:1.5.1.RELEASE| | +--- org.springframework:spring-core:4.3.6.RELEASE| | \--- org.springframework:spring-context:4.3.6.RELEASE| | +--- org.springframework:spring-aop:4.3.6.RELEASE| | | +--- org.springframework:spring-beans:4.3.6.RELEASE| | | | \--- org.springframework:spring-core:4.3.6.RELEASE| | | \--- org.springframework:spring-core:4.3.6.RELEASE| | +--- org.springframework:spring-beans:4.3.6.RELEASE (*)| | +--- org.springframework:spring-core:4.3.6.RELEASE| | \--- org.springframework:spring-expression:4.3.6.RELEASE| | \--- org.springframework:spring-core:4.3.6.RELEASE| +--- org.springframework.boot:spring-boot-autoconfigure:1.5.1.RELEASE| | \--- org.springframework.boot:spring-boot:1.5.1.RELEASE (*)| +--- org.springframework.boot:spring-boot-starter-logging:1.5.1.RELEASE| | +--- ch.qos.logback:logback-classic:1.1.9| | | +--- ch.qos.logback:logback-core:1.1.9| | | \--- org.slf4j:slf4j-api:1.7.22| | +--- org.slf4j:jcl-over-slf4j:1.7.22| | | \--- org.slf4j:slf4j-api:1.7.22| | +--- org.slf4j:jul-to-slf4j:1.7.22| | | \--- org.slf4j:slf4j-api:1.7.22| | \--- org.slf4j:log4j-over-slf4j:1.7.22| | \--- org.slf4j:slf4j-api:1.7.22| +--- org.springframework:spring-core:4.3.6.RELEASE| \--- org.yaml:snakeyaml:1.17+--- org.mongodb:mongodb-driver:3.4.1| +--- org.mongodb:mongodb-driver-core:3.4.1| | \--- org.mongodb:bson:3.4.1| \--- org.mongodb:bson:3.4.1\--- org.springframework.data:spring-data-mongodb:1.10.0.RELEASE+--- org.springframework:spring-tx:4.3.6.RELEASE| +--- org.springframework:spring-beans:4.3.6.RELEASE (*)| \--- org.springframework:spring-core:4.3.6.RELEASE+--- org.springframework:spring-context:4.3.6.RELEASE (*)+--- org.springframework:spring-beans:4.3.6.RELEASE (*)+--- org.springframework:spring-core:4.3.6.RELEASE+--- org.springframework:spring-expression:4.3.6.RELEASE (*)+--- org.springframework.data:spring-data-commons:1.13.0.RELEASE| +--- org.springframework:spring-core:4.3.6.RELEASE| +--- org.springframework:spring-beans:4.3.6.RELEASE (*)| +--- org.slf4j:slf4j-api:1.7.22| \--- org.slf4j:jcl-over-slf4j:1.7.22 (*)+--- org.slf4j:slf4j-api:1.7.22\--- org.slf4j:jcl-over-slf4j:1.7.22 (*)
3.MongoDB 配置
application.properties
#mongodb
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=app1#logging
logging.level.org.springframework.data=debug
logging.level.=error
4.Spring 数据–mongo repository
4.1 带有 Spring 数据注释的简单模型。
Domain.java
package com.mkyong.domain;import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;@Document(collection = "domain")
public class Domain {@Idprivate long id;@Indexed(unique = true)private String domain;private boolean displayAds;//getters and setters
}
4.2 扩展MongoRepository
,自动拥有 CRUD 功能。Spring 数据附带了许多神奇的findBy
查询,查看官方Spring data MongoDB–查询方法了解详情。
DomainRepository.java
package com.mkyong.domain;import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;import java.util.List;// No need implementation, just one interface, and you have CRUD, thanks Spring Data
public interface DomainRepository extends MongoRepository<Domain, Long> {Domain findFirstByDomain(String domain);Domain findByDomainAndDisplayAds(String domain, boolean displayAds);//Supports native JSON query string@Query("{domain:'?0'}")Domain findCustomByDomain(String domain);@Query("{domain: { $regex: ?0 } })")List<Domain> findCustomByRegExDomain(String domain);}
4.3 要为DomainRepository
创建自定义方法,您需要在另一个文件中创建实现,并让DomainRepository
扩展它。
以下示例将自定义的“更新特定字段”方法添加到MongoRepository
自定义界面
DomainRepositoryCustom.java
package com.mkyong.domain;public interface DomainRepositoryCustom {int updateDomain(String domain, boolean displayAds);}
4.3.2 实现类的名字很严格,名字必须是"CoreRepositoryInterface" + Impl
,读这个 Spring data MongoDB 自定义实现
DomainRepositoryCustom.java
package com.mkyong.domain;import com.mongodb.WriteResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;//Impl postfix of the name on it compared to the core repository interface
public class DomainRepositoryImpl implements DomainRepositoryCustom {@AutowiredMongoTemplate mongoTemplate;@Overridepublic int updateDomain(String domain, boolean displayAds) {Query query = new Query(Criteria.where("domain").is(domain));Update update = new Update();update.set("displayAds", displayAds);WriteResult result = mongoTemplate.updateFirst(query, update, Domain.class);if(result!=null)return result.getN();elsereturn 0;}
}
4.3.3 DomainRepository
扩展自定义接口DomainRepositoryCustom
DomainRepository.java
package com.mkyong.domain;import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;import java.util.List;public interface DomainRepository extends MongoRepository<Domain, Long>, DomainRepositoryCustom {//other methods}
5.奔跑
5.1 Spring Boot 应用程序。
Application.java
package com.mkyong;import com.mkyong.domain.Domain;
import com.mkyong.domain.DomainRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}@BeanCommandLineRunner init(DomainRepository domainRepository) {return args -> {Domain obj = domainRepository.findOne(7L);System.out.println(obj);Domain obj2 = domainRepository.findFirstByDomain("mkyong.com");System.out.println(obj2);int n = domainRepository.updateDomain("mkyong.com", true);System.out.println("Number of records updated : " + n);};}}
5.2 Gradle 构建并运行它。
Terminal
$ gradle build$ java -jar build/libs/spring-data-mongodb-example-1.0.jar. ____ _ __ _ _/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/ ___)| |_)| | | | | || (_| | ) ) ) )' |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot :: (v1.5.1.RELEASE)//blah blah blah
6.常见问题
6.1 如何创建自定义MongoTemple
?
答:声明一个新的MongoTemplate
bean 来覆盖默认值。在下面的例子中,它创建了一个自定义的MongoTemplate
来删除_class
字段。
Application.java
package com.mkyong;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}//remove _class@Beanpublic MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory,MongoMappingContext context) {MappingMongoConverter converter =new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory), context);converter.setTypeMapper(new DefaultMongoTypeMapper(null));MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory, converter);return mongoTemplate;}}
下载源代码
Download – spring-boot-data-mongodb-example.zip (7 KB)
参考
- Spring Data MongoDB–参考文档
- 与 NoSQL 科技合作
- Spring Boot Gradle 插件
- 用 Spring Boot 构建应用
- Gradle–显示项目相关性
gradle mongodb spring boot spring-data
Spring Boot +春季安全+百里香示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-spring-security-thymeleaf-example/
一个 Spring Boot 百里香的例子,使用 Spring 安全来保护路径/admin
和/user
使用的技术:
- Spring Boot 1.5.3 版本
- 弹簧 4.3.8 .释放
- 春季安全 4.2.2
- 百里香叶
- 百里香额外春季安全 4 2.1.3
- Tomcat Embed 8.5.14
- maven3
- Java 8
1.项目目录
2.项目相关性
声明spring-boot-starter-security
,它将获得开发Spring Boot + Spring Security
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-spring-security</artifactId><packaging>jar</packaging><name>Spring Boot Web Spring Security</name><description>Spring Boot Web Spring Security 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.3.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><!-- Spring Security --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- do you like thymeleaf? --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- optional, it brings userful tags to display spring security stuff --><dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity4</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><!-- 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 Spring Security 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.10:tree (default-cli) @ spring-boot-web-spring-security ---
[INFO] org.springframework.boot:spring-boot-web-spring-security:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-thymeleaf:jar:1.5.3.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:1.5.3.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:1.5.3.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.25:compile
[INFO] | | | +- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
[INFO] | | | \- org.slf4j:log4j-over-slf4j:jar:1.7.25:compile
[INFO] | | +- org.springframework:spring-core:jar:4.3.8.RELEASE:compile
[INFO] | | \- org.yaml:snakeyaml:jar:1.17:runtime
[INFO] | +- org.springframework.boot:spring-boot-starter-web:jar:1.5.3.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-tomcat:jar:1.5.3.RELEASE:compile
[INFO] | | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.14:compile
[INFO] | | | +- org.apache.tomcat.embed:tomcat-embed-el:jar:8.5.14:compile
[INFO] | | | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.5.14:compile
[INFO] | | +- org.hibernate:hibernate-validator:jar:5.3.5.Final:compile
[INFO] | | | +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO] | | | +- org.jboss.logging:jboss-logging:jar:3.3.1.Final:compile
[INFO] | | | \- com.fasterxml:classmate:jar:1.3.3:compile
[INFO] | | +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.8:compile
[INFO] | | | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.0:compile
[INFO] | | | \- com.fasterxml.jackson.core:jackson-core:jar:2.8.8:compile
[INFO] | | +- org.springframework:spring-web:jar:4.3.8.RELEASE:compile
[INFO] | | \- org.springframework:spring-webmvc:jar:4.3.8.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.21.0-GA:compile
[INFO] | | \- org.unbescape:unbescape:jar:1.1.0.RELEASE:compile
[INFO] | \- nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:jar:1.4.0:compile
[INFO] | \- org.codehaus.groovy:groovy:jar:2.4.10:compile
[INFO] +- org.springframework.boot:spring-boot-starter-security:jar:1.5.3.RELEASE:compile
[INFO] | +- org.springframework:spring-aop:jar:4.3.8.RELEASE:compile
[INFO] | | \- org.springframework:spring-beans:jar:4.3.8.RELEASE:compile
[INFO] | +- org.springframework.security:spring-security-config:jar:4.2.2.RELEASE:compile
[INFO] | | +- org.springframework.security:spring-security-core:jar:4.2.2.RELEASE:compile
[INFO] | | \- org.springframework:spring-context:jar:4.3.8.RELEASE:compile
[INFO] | \- org.springframework.security:spring-security-web:jar:4.2.2.RELEASE:compile
[INFO] | \- org.springframework:spring-expression:jar:4.3.8.RELEASE:compile
[INFO] +- org.thymeleaf.extras:thymeleaf-extras-springsecurity4:jar:2.1.3.RELEASE:compile
[INFO] | \- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] +- org.springframework.boot:spring-boot-devtools:jar:1.5.3.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot:jar:1.5.3.RELEASE:compile
[INFO] | \- org.springframework.boot:spring-boot-autoconfigure:jar:1.5.3.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: 2.072 s
[INFO] Finished at: 2017-05-04T10:13:05+08:00
[INFO] Final Memory: 19M/309M
[INFO] ------------------------------------------------------------------------
3.春天安全
3.1 扩展了WebSecurityConfigurerAdapter
,在configure
方法中定义了安全规则。
对于用户“管理员”:
- 能够访问
/admin
页面 - 无法访问
/user
页面,重定向至 403 拒绝访问页面。
对于用户“用户”:
- 能够访问
/user
页面 - 无法访问
/admin
页面,重定向至 403 拒绝访问页面。
SpringSecurityConfig.java
package com.mkyong.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.AccessDeniedHandler;@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate AccessDeniedHandler accessDeniedHandler;// roles admin allow to access /admin/**// roles user allow to access /user/**// custom 403 access denied handler@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/", "/home", "/about").permitAll().antMatchers("/admin/**").hasAnyRole("ADMIN").antMatchers("/user/**").hasAnyRole("USER").anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll().and().logout().permitAll().and().exceptionHandling().accessDeniedHandler(accessDeniedHandler);}// create two users, admin and user@Autowiredpublic void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("user").password("password").roles("USER").and().withUser("admin").password("password").roles("ADMIN");}
}
3.2 自定义 403 拒绝访问处理程序,记录请求并重定向至/403
WelcomeController.java
package com.mkyong.error;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;// handle 403 page
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {private static Logger logger = LoggerFactory.getLogger(MyAccessDeniedHandler.class);@Overridepublic void handle(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,AccessDeniedException e) throws IOException, ServletException {Authentication auth= SecurityContextHolder.getContext().getAuthentication();if (auth != null) {logger.info("User '" + auth.getName()+ "' attempted to access the protected URL: "+ httpServletRequest.getRequestURI());}httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/403");}
}
4.Spring Boot
4.1 一个控制器类,用来定义 http 请求和视图名。
DefaultController.java
package com.mkyong.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;@Controller
public class DefaultController {@GetMapping("/")public String home1() {return "/home";}@GetMapping("/home")public String home() {return "/home";}@GetMapping("/admin")public String admin() {return "/admin";}@GetMapping("/user")public String user() {return "/user";}@GetMapping("/about")public String about() {return "/about";}@GetMapping("/login")public String login() {return "/login";}@GetMapping("/403")public String error403() {return "/error/403";}}
4.2 启动 Spring Boot 应用程序。
DefaultController.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);}}
5.百里香+资源+静态文件
5.1 百里香文件放在src/main/resources/templates/
文件夹中。
5.2 百里香叶碎片,用于模板布局-标题。
src/main/resources/templates/fragments/header.html
<html xmlns:th="http://www.thymeleaf.org">
<head><div th:fragment="header-css"><!-- this is header-css --><link rel="stylesheet" type="text/css"href="webjars/bootstrap/3.3.7/css/bootstrap.min.css" /><link rel="stylesheet" th:href="@{/css/main.css}"href="../../css/main.css" /></div>
</head>
<body>
<div th:fragment="header"><!-- this is header --><nav class="navbar navbar-inverse"><div class="container"><div class="navbar-header"><a class="navbar-brand" th:href="@{/}">Spring Boot</a></div><div id="navbar" class="collapse navbar-collapse"><ul class="nav navbar-nav"><li class="active"><a th:href="@{/}">Home</a></li></ul></div></div></nav>
</div></body>
</html>
5.3 百里香叶碎片,用于模板布局-页脚。查看sec
标签,这是一个有用的标签来展示弹簧安全的东西,详情请参考这个百里香叶加春安全。
src/main/resources/templates/fragments/footer.html
<html xmlns:th="http://www.thymeleaf.org"xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
</head>
<body>
<div th:fragment="footer"><div class="container"><footer><!-- this is footer -->© 2017 mkyong.com<span sec:authorize="isAuthenticated()">| Logged user: <span sec:authentication="name"></span> |Roles: <span sec:authentication="principal.authorities"></span> |<a th:href="@{/logout}">Sign Out</a></span><script type="text/javascript"src="webjars/bootstrap/3.3.7/js/bootstrap.min.js"></script></footer></div></div>
</body>
</html>
5.4 百里香文件列表,没什么特别的,不言自明。
家~
src/main/resources/templates/home.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>Spring Boot Thymeleaf + Spring Security</title><div th:replace="fragments/header :: header-css"/></head>
<body><div th:replace="fragments/header :: header"/><div class="container"><div class="starter-template"><h1>Spring Boot Web Thymeleaf + Spring Security</h1><h2>1\. Visit <a th:href="@{/admin}">Admin page (Spring Security protected, Need Admin Role)</a></h2><h2>2\. Visit <a th:href="@{/user}">User page (Spring Security protected, Need User Role)</a></h2><h2>3\. Visit <a th:href="@{/about}">Normal page</a></h2></div></div>
<!-- /.container --><div th:replace="fragments/footer :: footer"/></body>
</html>
admin ~
src/main/resources/templates/admin.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head><div th:replace="fragments/header :: header-css"/>
</head>
<body><div th:replace="fragments/header :: header"/><div class="container"><div class="starter-template"><h1>Admin page (Spring Security protected)</h1><h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1><form th:action="@{/logout}" method="post"><input type="submit" value="Sign Out"/></form></div></div>
<!-- /.container --><div th:replace="fragments/footer :: footer"/></body>
</html>
用户~
src/main/resources/templates/user.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head><div th:replace="fragments/header :: header-css"/>
</head>
<body><div th:replace="fragments/header :: header"/><div class="container"><div class="starter-template"><h1>User page (Spring Security protected)</h1><h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1><form th:action="@{/logout}" method="post"><input type="submit" value="Sign Out"/></form></div></div>
<!-- /.container -->
<div th:replace="fragments/footer :: footer"/></body>
</html>
关于~
src/main/resources/templates/about.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head><div th:replace="fragments/header :: header-css"/>
</head>
<body><div th:replace="fragments/header :: header"/><div class="container"><div class="starter-template"><h1>Normal page (No need login)</h1></div></div>
<!-- /.container --><div th:replace="fragments/footer :: footer"/></body>
</html>
登录~
src/main/resources/templates/login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
>
<head><title>Spring Security Example </title><div th:replace="fragments/header :: header-css"/>
</head>
<body><div th:replace="fragments/header :: header"/><div class="container"><div class="row" style="margin-top:20px"><div class="col-xs-12 col-sm-8 col-md-6 col-sm-offset-2 col-md-offset-3"><form th:action="@{/login}" method="post"><fieldset><h1>Please Sign In</h1><div th:if="${param.error}"><div class="alert alert-danger">Invalid username and password.</div></div><div th:if="${param.logout}"><div class="alert alert-info">You have been logged out.</div></div><div class="form-group"><input type="text" name="username" id="username" class="form-control input-lg"placeholder="UserName" required="true" autofocus="true"/></div><div class="form-group"><input type="password" name="password" id="password" class="form-control input-lg"placeholder="Password" required="true"/></div><div class="row"><div class="col-xs-6 col-sm-6 col-md-6"><input type="submit" class="btn btn-lg btn-primary btn-block" value="Sign In"/></div><div class="col-xs-6 col-sm-6 col-md-6"></div></div></fieldset></form></div></div></div><div th:replace="fragments/footer :: footer"/></body>
</html>
403 ~
src/main/resources/templates/error/403.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head><div th:replace="fragments/header :: header-css"/>
</head>
<body><div th:replace="fragments/header :: header"/><div class="container"><div class="starter-template"><h1>403 - Access is denied</h1><div th:inline="text">Hello '[[${#httpServletRequest.remoteUser}]]', you do not have permission to access this page.</div></div></div>
<!-- /.container --><div th:replace="fragments/footer :: footer"/></body>
</html>
5.5 对于 CSS 或 Javascript 等静态文件,放入/src/main/resources/static/
/src/main/resources/static/css/main.css
h1{color:#0000FF;
}h2{color:#FF0000;
}footer{margin-top:60px;
}
Note
Read this Spring Boot Serving static content to understand the resource mapping.
6.演示
6.1 启动 Spring Boot 网络应用程序。此/admin/**
受保护,您需要以管理员身份登录才能访问。
Terminal
$ mvn spring-boot:run//...
6.2 访问http://localhost:8080
6.3 访问http://localhost:8080/admin
,重定向至http://localhost:8080/login
6.4 无效的用户名或密码http://localhost:8080/login
6.5 登录成功,重定向回管理页面http://localhost:8080/admin
,查看页脚部分,显示用户信息。
6.6 访问http://localhost:8080/user
,重定向至http://localhost:8080/403
6.7 单击页脚的注销链接,重定向至http://localhost:8080/login?logout
完成了。尝试用另一个用户名“user”登录并访问管理页面。
下载源代码
Download it – spring-boot-spring-security-thymeleaf.zip (15 KB)
参考
- 保护网络应用
- 春季安全参考
- Spring Boot 安全特征
- Spring Boot Hello World 示例–百里香叶
- 春安你好世界注释示例
- 百里香 Spring 安全集成基础知识
- 百里香叶 extra-Spring 安全集成基础知识
- 百里香叶–标准 URL 语法
- Spring Boot+Spring MVC+Spring Security+MySQL
- Spring Boot–静态内容
- spring MVC–in ucci CSS 文件
Spring Boot 测试–如何禁用调试和信息日志
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-test-how-to-stop-debug-logs/
运行 Spring Boot 集成测试或单元测试,许多恼人的调试和信息日志显示在控制台中。
用 Spring Boot 2 号进行了测试
Console
2019-03-04 13:15:25.151 INFO --- [ main] .b.t.c.SpringBootTestContextBootstrapper :
2019-03-04 13:15:25.157 INFO --- [ main] o.s.t.c.support.AbstractContextLoader :
2019-03-04 13:15:25.158 INFO --- [ main] t.c.s.AnnotationConfigContextLoaderUtils :
2019-03-04 13:15:25.298 INFO --- [ main] .b.t.c.SpringBootTestContextBootstrapper :
2019-03-04 13:15:25.401 INFO --- [ main] .b.t.c.SpringBootTestContextBootstrapper :
2019-03-04 13:15:25.430 INFO --- [ main] .b.t.c.SpringBootTestContextBootstrapper : . ____ _ __ _ _/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/ ___)| |_)| | | | | || (_| | ) ) ) )' |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot :: (v2.1.2.RELEASE)2019-03-04 13:15:25.886 DEBUG 7484 --- [ main] o.s.boot.SpringApplication :
2019-03-04 13:15:25.903 DEBUG 7484 --- [ main] o.s.b.c.c.ConfigFileApplicationListener :
2019-03-04 13:15:25.904 DEBUG 7484 --- [ main] o.s.b.c.c.ConfigFileApplicationListener :
2019-03-04 13:15:25.904 DEBUG 7484 --- [ main] o.s.b.c.c.ConfigFileApplicationListener :
2019-03-04 13:15:25.905 DEBUG 7484 --- [ main] o.s.w.c.s.GenericWebApplicationContext :
2019-03-04 13:15:25.922 DEBUG 7484 --- [ main] o.s.b.f.s.DefaultListableBeanFactory :
2019-03-04 13:15:25.937 DEBUG 7484 --- [ main] o.s.b.f.s.DefaultListableBeanFactory :
2019-03-04 13:15:26.004 DEBUG 7484 --- [ main] o.s.c.a.ClassPathBeanDefinitionScanner :
解决办法
要禁用日志,关闭application.properties
和logback-test.xml
中的logging.level
1.1 在application.properties
中关闭记录
application.properties
logging.level.org.springframework=OFF
logging.level.root=OFF
Spring 横幅下面的调试或信息日志现在关闭了。
Console
2019-03-04 13:15:25.151 INFO --- [ main] .b.t.c.SpringBootTestContextBootstrapper :
2019-03-04 13:15:25.157 INFO --- [ main] o.s.t.c.support.AbstractContextLoader :
2019-03-04 13:15:25.158 INFO --- [ main] t.c.s.AnnotationConfigContextLoaderUtils :
2019-03-04 13:15:25.298 INFO --- [ main] .b.t.c.SpringBootTestContextBootstrapper :
2019-03-04 13:15:25.401 INFO --- [ main] .b.t.c.SpringBootTestContextBootstrapper :
2019-03-04 13:15:25.430 INFO --- [ main] .b.t.c.SpringBootTestContextBootstrapper : . ____ _ __ _ _/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/ ___)| |_)| | | | | || (_| | ) ) ) )' |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot :: (v2.1.2.RELEASE)
1.2 在src/test/resources
中创建一个logback-test.xml
。同样,在这里关闭日志记录。
logback-test.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration><include resource="org/springframework/boot/logging/logback/base.xml" /><logger name="org.springframework" level="OFF"/>
</configuration>
好,就留下春横幅。
Console
. ____ _ __ _ _/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/ ___)| |_)| | | | | || (_| | ) ) ) )' |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot :: (v2.1.2.RELEASE)
1.3 关闭弹簧横幅。
application.properties
logging.level.org.springframework=OFF
logging.level.root=OFF
spring.main.banner-mode=off
完成,控制台现在应该是空的。
参考
- Spring Boot——伐木
- 测试 Spring Boot 应用
- logback.xml 示例
- log back–在单元测试中禁用日志记录
Spring Boot 测试无法自动连线 MockMvc
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-test-unable-to-autowired-mockmvc/
Spring Boot 积分测试,但无法@Autowired MockMvc
PS 用 Spring Boot 2.1.2.RELEASE 测试
BookControllerTest.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.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class BookControllerTest {@Autowiredprivate MockMvc mockMvc; //null?@Testpublic void findOne() throws Exception {mockMvc.perform(get("/books/1")).andDo(print()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)).andExpect(status().isOk()).andExpect(jsonPath("$.id", is(1)));}}
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.test.web.servlet.MockMvc' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}//...... 28 more
解决办法
添加此@AutoConfigureMockMvc
来启用和配置MockMvc
的自动配置
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.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc //need this in Spring Boot test
public class BookControllerTest {@Autowiredprivate MockMvc mockMvc;@Testpublic void findOne() throws Exception {mockMvc.perform(get("/books/1")).andDo(print()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)).andExpect(status().isOk()).andExpect(jsonPath("$.id", is(1)));}}
参考
- 自动配置模型 Mvc 文档
- 测试网页层
- 测试网页层
- @ autoconfigureweb MVC 和@AutoConfigureMockMvc 有什么区别?
mock MockMvc spring boot spring test (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/20190308020137/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
Spring Boot 教程
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/tutorials/spring-boot-tutorials/
Spring Boot 让创建一个基于 Spring 的应用变得简单快捷。
PS 用 Spring Boot 2.1.2.RELEASE 测试
1.Spring MVC 或 Web 应用程序。
- Spring Boot MVC Hello World 示例–百里香叶
- Spring MVC 验证示例
- Spring MVC + Spring 安全示例
- Spring MVC 表单处理示例
- Spring MVC 集成测试示例
- Spring MVC + Spring Security 示例 需要更新
- Spring MVC + Spring Security +通过数据库登录
- Spring MVC——为部署创建一个 WAR 文件
- Kotlin + Spring MVC 示例
2.Spring RESTful web 服务
- 春歇你好天下例
- 弹簧座验证示例
- 弹簧座+弹簧安全示例
- 弹簧座错误处理示例
- 弹簧支架集成测试示例
- Kotlin +弹簧座示例
3.弹簧网流量
- Spring WebFlux + Server-sent 事件示例
- Spring WebFlux +百里香叶反应示例
- Spring WebFlux + Spring 安全示例
- Spring WebFlux 集成测试示例
- Kotlin + Spring WebFlux 示例
4.外部化配置
- Spring Boot @配置属性示例
- Spring Boot YAML 的例子
- Spring Boot 简介示例
- 基于 Spring Boot 个人资料的属性和 YAML 示例
5.使用数据库
5.1 春季数据 JPA 示例。
- Spring Boot +春季数据 JPA
- Spring Boot+Spring data JPA+MySQL
- Spring Boot +春季数据 JPA + PostgreSQL
5.2 春 JDBC JdbcTemplate
举例。
- Spring Boot JDBC 的例子
- Spring Boot JDBC 存储过程示例
- Spring JdbcTemplate 查询示例
- Spring JDBC template Handle Large ResultSet
- Spring JDBC template batch update()示例
- Spring Boot JDBC 图像斑点示例
需要更新
- Spring Boot+Spring Data JPA+Oracle 示例
- Spring Boot JDBC + Oracle 数据库+ Commons DBCP2 示例
- Spring Boot JDBC+MySQL+HikariCP 的例子
6.记录
- Spring Boot Log4j 2 例
- Spring Boot SLF4j 回退示例
常见问题
- Spring Boot——如何通过 SMTP 发送电子邮件
- Spring Boot +朱尼特 5 +莫奇托
- Spring Boot 测试–如何禁用调试和信息日志
- Spring Boot 测试无法自动连线 MockMvc
- Spring Boot——如何初始化用于测试的 Bean】
- Spring Test——如何在 jsonPath 中测试 JSON 数组
- Spring Boot–应用程序启动时运行代码
- Spring WebFlux 测试–阻塞读取超时 5000 毫秒
- Spring Security–没有为 id“null”映射 PasswordEncoder
- Spring Boot+mock ITO–无法模仿保存方法?
- Spring Boot+mock ITO–when()需要一个必须是“模拟上的方法调用”的参数。
- Spring Boot——开始哪个主班
- Spring–如何从资源文件夹中读取文件
将下面的教程升级到 Spring Boot 2
PS 在 Spring Boot 1.4.x 上测试
-
Spring Boot Hello World 示例——小胡子
-
Spring Boot Hello World 示例–JSP
-
Spring Boot+Spring Security+oauth 2 示例
-
Spring Boot 非 web 应用实例
-
Spring Boot @配置属性示例
-
Spring Boot SLF4J 测井示例
-
Spring Boot Ajax 示例
-
Spring Boot 文件上传示例–Ajax 和 REST
-
Spring Boot 文件上传示例
-
Spring Boot——如何知道使用了哪个连接池?
-
Spring Boot + Spring 数据 MongoDB 示例
-
Spring Boot +春季数据 JPA + Java 8 日期和时间(JSR310)
-
Spring Boot–显示 Hibernate SQL 查询
-
Spring Boot——作为嵌入式服务器的 Jetty
-
Spring Boot——如何更改 Tomcat 端口
-
Spring Boot——如何改变上下文路径
-
Spring Boot–定制横幅示例
-
Spring Boot——在嵌入式 Tomcat 中配置 maxSwallowSize
-
Intellij IDEA–Spring boot 模板重新加载不起作用
-
如何显示 Spring Boot 加载的所有 beans】
-
Spring Boot——如何禁用 Spring 标志横幅
-
Spring Boot web JSP–没有可用的 Java 编译器
下载源代码
$ git clone https://github.com/mkyong/spring-boot.git
参考
- Spring Boot 参考指南
- Spring 初始化器——现在启动你的应用程序
Spring Boot web JSP–没有可用的 Java 编译器
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-web-jsp-no-java-compiler-available/
内嵌 Tomcat 和 JSP 的 Spring boot web 应用程序。运行并访问 JSP 页面,但是遇到以下错误
$ mvn spring-boot:run
...
java.lang.IllegalStateException: No Java compiler availableat org.apache.jasper.JspCompilationContext.createCompiler(JspCompilationContext.java:235) ~[tomcat-embed-jasper-8.5.6.jar:8.5.6]at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:592) ~[tomcat-embed-jasper-8.5.6.jar:8.5.6]at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:368) ~[tomcat-embed-jasper-8.5.6.jar:8.5.6]at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:385) ~[tomcat-embed-jasper-8.5.6.jar:8.5.6]at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:329) ~[tomcat-embed-jasper-8.5.6.jar:8.5.6]at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) [tomcat-embed-core-8.5.6.jar:8.5.6]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) [tomcat-embed-core-8.5.6.jar:8.5.6]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [tomcat-embed-core-8.5.6.jar:8.5.6]at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-embed-websocket-8.5.6.jar:8.5.6]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) [tomcat-embed-core-8.5.6.jar:8.5.6]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [tomcat-embed-core-8.5.6.jar:8.5.6]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) [spring-web-4.3.4.RELEASE.jar:4.3.4.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
环境:
- Spring Boot 1.4.2 版本
- Tomcat Embed 8.5.6
1.Spring Boot 环境
要编译 JSP,需要tomcat-embed-jasper
。
pom.xml
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.4.2.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency></dependencies>
显示项目相关性:
$ mvn dependency:tree[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] +- org.apache.tomcat.embed:tomcat-embed-jasper:jar:8.5.6:provided
[INFO] | \- org.eclipse.jdt.core.compiler:ecj:jar:4.5.1:provided
[INFO] \- javax.servlet:jstl:jar:1.2:compile
2.解决办法
不知道为什么tomcat-embed-jasper
没有使用 ecj 编译器,为了解决这个问题,Eclipse ecj
手动声明:
pom.xml
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.4.2.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><!-- Add this --><dependency><groupId>org.eclipse.jdt.core.compiler</groupId><artifactId>ecj</artifactId><version>4.6.1</version><scope>provided</scope></dependency></dependencies>
显示项目相关性:
$ mvn dependency:tree[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] +- org.apache.tomcat.embed:tomcat-embed-jasper:jar:8.5.6:provided
[INFO] +- javax.servlet:jstl:jar:1.2:compile
[INFO] \- org.eclipse.jdt.core.compiler:ecj:jar:4.6.1:provided
参考
- 使用嵌入式 Tomcat 创建一个 Java Web 应用程序
- Jasper 2 JSP 引擎如何
- 可怕的没有可用的 Java 编译器
Spring Boot WebFlux +服务器发送的事件示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-webflux-server-sent-events-example/
在本文中,我们将向您展示如何使用服务器发送的事件开发一个反应式 web 应用程序
- Spring Boot 2.1.2 .版本
- Spring WebFlux 5.1.4 .发行版
- 百里香叶
- JUnit 5.3.2
- maven3
在 Spring 中,返回 JSON 和 header MediaType.TEXT_EVENT_STREAM_VALUE
@RestController
public class CommentController {@GetMapping(path = "/comment/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<Comment> feed() {//...}}
在 Javascript 中,使用EventSource
向上述端点发送请求。
function loadComments () {this.source = null;this.start = function () {this.source = new EventSource("/comment/stream");this.source.addEventListener("message", function (event) {var comment = JSON.parse(event.data);//... update somewhere});this.source.onerror = function () {this.close();};};this.stop = function() {this.source.close();}}comment = new loadComments();window.onload = function() {comment.start();
};
window.onbeforeunload = function() {comment.stop();
}
1.项目目录
## 2.专家
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><groupId>com.mkyong.spring.reactive</groupId><artifactId>webflux-thymeleaf-sse</artifactId><version>1.0</version><properties><java.version>1.8</java.version><junit-jupiter.version>5.3.2</junit-jupiter.version></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version></parent><dependencies><!-- webflux reactive --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><!-- thymeleaf --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- exclude junit 4, prefer junit 5 --><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.reactive:webflux-thymeleaf-sse:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-webflux: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-reactor-netty:jar:2.1.2.RELEASE:compile
[INFO] | | \- io.projectreactor.netty:reactor-netty:jar:0.8.4.RELEASE:compile
[INFO] | | +- io.netty:netty-codec-http:jar:4.1.31.Final:compile
[INFO] | | | \- io.netty:netty-codec:jar:4.1.31.Final:compile
[INFO] | | +- io.netty:netty-codec-http2:jar:4.1.31.Final:compile
[INFO] | | +- io.netty:netty-handler:jar:4.1.31.Final:compile
[INFO] | | | +- io.netty:netty-buffer:jar:4.1.31.Final:compile
[INFO] | | | \- io.netty:netty-transport:jar:4.1.31.Final:compile
[INFO] | | | \- io.netty:netty-resolver:jar:4.1.31.Final:compile
[INFO] | | +- io.netty:netty-handler-proxy:jar:4.1.31.Final:compile
[INFO] | | | \- io.netty:netty-codec-socks:jar:4.1.31.Final:compile
[INFO] | | \- io.netty:netty-transport-native-epoll:jar:linux-x86_64:4.1.31.Final:compile
[INFO] | | +- io.netty:netty-common:jar:4.1.31.Final:compile
[INFO] | | \- io.netty:netty-transport-native-unix-common:jar:4.1.31.Final: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-webflux:jar:5.1.4.RELEASE:compile
[INFO] | | \- io.projectreactor:reactor-core:jar:3.2.5.RELEASE:compile
[INFO] | | \- org.reactivestreams:reactive-streams:jar:1.0.2:compile
[INFO] | \- org.synchronoss.cloud:nio-multipart-parser:jar:1.1.0:compile
[INFO] | +- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] | \- org.synchronoss.cloud:nio-stream-storage:jar:1.1.3: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.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] | +- 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.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: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
3.Spring Boot +春网流量
3.1 基于 Spring WebFlux 注释的控制器。启用数据流。写produces = MediaType.TEXT_EVENT_STREAM_VALUE
CommentController.java
package com.mkyong.reactive.controller;import com.mkyong.reactive.model.Comment;
import com.mkyong.reactive.repository.CommentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;@RestController
public class CommentController {@Autowiredprivate CommentRepository commentRepository;@GetMapping(path = "/comment/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<Comment> feed() {return this.commentRepository.findAll();}}
MainController.java
package com.mkyong.reactive.controller;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;@Controller
public class MainController {@GetMapping("/")public String index(final Model model) {return "index";}}
3.2 在repository
中,返回一个Flux
对象。
CommentRepository.java
package com.mkyong.reactive.repository;import com.mkyong.reactive.model.Comment;
import reactor.core.publisher.Flux;public interface CommentRepository {Flux<Comment> findAll();}
ReactiveCommentRepository.java
package com.mkyong.reactive.repository;import com.mkyong.reactive.model.Comment;
import com.mkyong.reactive.utils.CommentGenerator;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;import java.time.Duration;
import java.util.Arrays;
import java.util.List;@Repository
public class ReactiveCommentRepository implements CommentRepository {@Overridepublic Flux<Comment> findAll() {//simulate data streaming every 1 second.return Flux.interval(Duration.ofSeconds(1)).onBackpressureDrop().map(this::generateComment).flatMapIterable(x -> x);}private List<Comment> generateComment(long interval) {Comment obj = new Comment(CommentGenerator.randomAuthor(), CommentGenerator.randomMessage(), CommentGenerator.getCurrentTimeStamp());return Arrays.asList(obj);}}
3.3 生成随机注释的 utils 类。
CommentGenerator.java
package com.mkyong.reactive.utils;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Random;public class CommentGenerator {private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");private static final Random RANDOM = new Random(System.currentTimeMillis());private static final List<String> COMMENT_AUTHOR =Arrays.asList("Mkyong", "Oliver", "Jack", "Harry", "Jacob","Isla", "Emily", "Poppy", "Ava", "Isabella");private static final List<String> COMMENT_MESSAGE =Arrays.asList("I Love this!","Me too!","Wow","True!","Hello everyone here?","Good!");public static String randomAuthor() {return COMMENT_AUTHOR.get(RANDOM.nextInt(COMMENT_AUTHOR.size()));}public static String randomMessage() {return COMMENT_MESSAGE.get(RANDOM.nextInt(COMMENT_MESSAGE.size()));}public static String getCurrentTimeStamp() {return dtf.format(LocalDateTime.now());}
}
3.4 评论模式。
Movie.java
package com.mkyong.reactive.model;public class Comment {private String author;private String message;private String timestamp;//getter, setter and constructor
}
3.5 开始 Spring Boot。
CommentWebApplication.java
package com.mkyong.reactive;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class CommentWebApplication {public static void main(String[] args) {SpringApplication.run(CommentWebApplication.class, args);}}
4.百里香叶
百里香模板中没有特殊的反应标签,只是使用了普通的循环。
resources/templates/index.html
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><link data-th-href="@{/css/bootstrap.min.css}" rel="stylesheet"><link data-th-href="@{/css/main.css}" rel="stylesheet">
</head>
<body><div class="container"><div class="row"><div id="title"><h1>Spring WebFlux + Server Sent Events</h1></div><table id="comments" class="table table-striped"><thead><tr><th width="10%">Author</th><th width="60%">Message</th><th width="30%">Date</th></tr></thead><tbody><tr class="result" data-th-each="comment : ${comments}"><td>[[${comment.author}]]</td><td>[[${comment.message}]]</td><td>[[${comment.timestamp}]]</td></tr></tbody></table></div></div><script data-th-src="@{/js/main.js}"></script></body></html>
5.JavaScript 事件源。
关键是使用 Javascript EventSource
类发送请求并监听message
事件,并将流数据反应性地更新到一个表中。
resources/static/js/main.js
function loadComments () {this.source = null;this.start = function () {var commentTable = document.getElementById("comments");this.source = new EventSource("/comment/stream");this.source.addEventListener("message", function (event) {// These events are JSON, so parsing and DOM fiddling are neededvar comment = JSON.parse(event.data);var row = commentTable.getElementsByTagName("tbody")[0].insertRow(0);var cell0 = row.insertCell(0);var cell1 = row.insertCell(1);var cell2 = row.insertCell(2);cell0.className = "author-style";cell0.innerHTML = comment.author;cell1.className = "text";cell1.innerHTML = comment.message;cell2.className = "date";cell2.innerHTML = comment.timestamp;});this.source.onerror = function () {this.close();};};this.stop = function() {this.source.close();}}comment = new loadComments();/** Register callbacks for starting and stopping the SSE controller.*/
window.onload = function() {comment.start();
};
window.onbeforeunload = function() {comment.stop();
}
6.单元测试
WebTestClient
对流响应进行单元测试
TestCommentWebApplication.java
package com.mkyong.reactive;import com.mkyong.reactive.model.Comment;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;import java.util.List;import static org.junit.jupiter.api.Assertions.assertEquals;@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class TestCommentWebApplication {@Autowiredprivate WebTestClient webClient;@Testpublic void testCommentStream() {List<Comment> comments = webClient.get().uri("/comment/stream").accept(MediaType.valueOf(MediaType.TEXT_EVENT_STREAM_VALUE)).exchange().expectStatus().isOk().returnResult(Comment.class).getResponseBody().take(3) // take 3 comment objects.collectList().block();comments.forEach(x -> System.out.println(x));assertEquals(3, comments.size());}}
7.演示
$ mvn spring-boot:run2019-02-11 15:41:17.657 INFO 257192 --- [ restartedMain] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080
URL =http://localhost:8080
数据是流式的,每 1 秒就会显示随机评论。
下载源代码
$ git clone https://github.com/mkyong/spring-boot.git
$ cd webflux-thymeleaf-serversentevent
$ mvn spring-boot:run
参考
- 事件来源
- 服务器发送的事件
- 使用服务器发送的事件
- 百里香叶与弹簧网反应
- Spring WebFlux Workshop
- Spring Boot WebFlux +百里香叶反应示例
- 写作测试–流响应
junit 5 reactive spring boot sse thymeleaf webflux
Spring Boot WebFlux +百里香叶反应实例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-webflux-thymeleaf-reactive-example/
在本文中,我们将向您展示如何开发一个反应式 web 应用程序。
- Spring Boot 2.1.2 .版本
- Spring WebFlux 5.1.4 .发行版
- 百里香叶
- maven3
Spring Boot 将配置一切,关键是使用百里香叶ReactiveDataDriverContextVariable
来启用百里香叶模板中的数据驱动模式。
@RequestMapping("/")public String index(final Model model) {// data streaming, data driven mode.IReactiveDataDriverContextVariable reactiveDataDrivenMode =new ReactiveDataDriverContextVariable(movieRepository.findAll(), 1);model.addAttribute("movies", reactiveDataDrivenMode);return "view";}
Note
Working on the Spring Boot WebFlux + Thymeleaf + Server-Sent Events (SSE) integeration. To be updated here.
1.项目目录
2.专家
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><groupId>com.mkyong.spring.reactive</groupId><artifactId>webflux-thymeleaf</artifactId><version>1.0</version><properties><java.version>1.8</java.version></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version></parent><dependencies><!-- reactive --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><!-- just include the normal thymeleaf --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><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></plugins></build></project>
显示项目依赖关系。
$ mvn dependency:tree[INFO] com.mkyong.spring.webflux:ReactiveApp:jar:1.0-SNAPSHOT
[INFO] +- org.springframework.boot:spring-boot-starter-webflux: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.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-reactor-netty:jar:2.1.2.RELEASE:compile
[INFO] | | \- io.projectreactor.netty:reactor-netty:jar:0.8.4.RELEASE:compile
[INFO] | | +- io.netty:netty-codec-http:jar:4.1.31.Final:compile
[INFO] | | | \- io.netty:netty-codec:jar:4.1.31.Final:compile
[INFO] | | +- io.netty:netty-codec-http2:jar:4.1.31.Final:compile
[INFO] | | +- io.netty:netty-handler:jar:4.1.31.Final:compile
[INFO] | | | +- io.netty:netty-buffer:jar:4.1.31.Final:compile
[INFO] | | | \- io.netty:netty-transport:jar:4.1.31.Final:compile
[INFO] | | | \- io.netty:netty-resolver:jar:4.1.31.Final:compile
[INFO] | | +- io.netty:netty-handler-proxy:jar:4.1.31.Final:compile
[INFO] | | | \- io.netty:netty-codec-socks:jar:4.1.31.Final:compile
[INFO] | | \- io.netty:netty-transport-native-epoll:jar:linux-x86_64:4.1.31.Final:compile
[INFO] | | +- io.netty:netty-common:jar:4.1.31.Final:compile
[INFO] | | \- io.netty:netty-transport-native-unix-common:jar:4.1.31.Final: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-webflux:jar:5.1.4.RELEASE:compile
[INFO] | | \- io.projectreactor:reactor-core:jar:3.2.5.RELEASE:compile
[INFO] | | \- org.reactivestreams:reactive-streams:jar:1.0.2:compile
[INFO] | \- org.synchronoss.cloud:nio-multipart-parser:jar:1.1.0:compile
[INFO] | +- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] | \- org.synchronoss.cloud:nio-stream-storage:jar:1.1.3: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.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
3.Spring Boot +春网流量
3.1 基于 Spring WebFlux 注释的控制器。用ReactiveDataDriverContextVariable
包装数据,将在百里香模板中启用反应式数据驱动模型。
MovieController.java
package com.mkyong.reactive.controller;import com.mkyong.reactive.repository.MovieRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.thymeleaf.spring5.context.webflux.IReactiveDataDriverContextVariable;
import org.thymeleaf.spring5.context.webflux.ReactiveDataDriverContextVariable;@Controller
public class MovieController {@Autowiredprivate MovieRepository movieRepository;@RequestMapping("/")public String index(final Model model) {// loads 1 and display 1, stream data, data driven mode.IReactiveDataDriverContextVariable reactiveDataDrivenMode =new ReactiveDataDriverContextVariable(movieRepository.findAll(), 1);model.addAttribute("movies", reactiveDataDrivenMode);// classic, wait repository loaded all and display it.//model.addAttribute("movies", movieRepository.findAll());return "index";}}
3.2 在repository
中,返回一个Flux
对象。
MovieRepository.java
package com.mkyong.reactive.repository;import com.mkyong.reactive.Movie;
import reactor.core.publisher.Flux;public interface MovieRepository {Flux<Movie> findAll();}
ReactiveMovieRepository.java
package com.mkyong.reactive.repository;import com.mkyong.reactive.Movie;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;import java.time.Duration;
import java.util.ArrayList;
import java.util.List;@Repository
public class ReactiveMovieRepository implements MovieRepository {private static List<Movie> movie = new ArrayList<>();static {movie.add(new Movie("Polar (2019)", 64));movie.add(new Movie("Iron Man (2008)", 79));movie.add(new Movie("The Shawshank Redemption (1994)", 93));movie.add(new Movie("Forrest Gump (1994)", 83));movie.add(new Movie("Glass (2019)", 70));}@Overridepublic Flux<Movie> findAll() {//Simulate big list of data, streaming it every 2 second delayreturn Flux.fromIterable(movie).delayElements(Duration.ofSeconds(2));}}
3.3 电影模式。
Movie.java
package com.mkyong.reactive;public class Movie {private String name;private Integer score;//getter, setter and constructor
}
3.4 启动 Spring Boot。
MovieWebApplication.java
package com.mkyong.reactive;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class MovieWebApplication {public static void main(String[] args) {SpringApplication.run(MovieWebApplication.class, args);}}
4.百里香叶
百里香模板中没有特殊的反应标签,只是使用了普通的循环。
resources/templates/index.html
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><link data-th-href="@{/css/bootstrap.min.css}" rel="stylesheet"><link data-th-href="@{/css/main.css}" rel="stylesheet">
</head>
<body><div class="container"><div class="row"><div id="title"><h1>Spring WebFlux + Thymeleaf</h1></div><table id="allMovies" class="table table-striped"><thead><tr><th width="70%">Name</th><th>Score</th></tr></thead><tbody><tr class="result" data-th-each="movie : ${movies}"><td>[[${movie.name}]]</td><td>[[${movie.score}]]</td></tr></tbody></table></div></div>
定义了块大小。
application.properties
spring.thymeleaf.reactive.max-chunk-size=8192
完成了。
5.演示
$ mvn spring-boot:run
URL =http://localhost:8080
数据是流式的,将每 2 秒钟以反应方式显示一次。
下载源代码
$ git clone https://github.com/mkyong/spring-boot.git
$ cd webflux-thymeleaf
$ mvn spring-boot:run
参考
- IReactiveDataDriverContextVariable
- 反应堆上的卷筒纸
- 百里香叶与弹簧网反应
- Spring WebFlux Workshop
Spring Boot——从哪门主课开始
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-which-main-class-to-start/
如果 Spring Boot 项目包含多个主类,Spring Boot 将无法启动或打包进行部署。
Terminal
$ mvn package
#or
$ mvn spring-boot:runFailed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.4.2.RELEASE:run (default-cli)
Execution default-cli of goal org.springframework.boot:spring-boot-maven-plugin:1.4.2.RELEASE:run failed:
Unable to find a single main class from the following candidates [com.mkyong.Test, com.mkyong.SpringBootWebApplication] -> [Help 1]
Maven 示例
1.1 通过start-class
属性定义单个主类
pom.xml
<properties><!-- The main class to start by executing java -jar --><start-class>com.mkyong.SpringBootWebApplication</start-class></properties>
1.2 或者,在spring-boot-maven-plugin
中定义主类
pom.xml
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><mainClass>com.mkyong.SpringBootWebApplication</mainClass></configuration></plugin></plugins></build>
参考
- Spring Boot——可执行的 jar 格式
- Spring Boot Maven 插件–用途
executable jar jar main class spring boot war (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/20190217051121/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
Spring Boot YAML 的例子
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-boot-yaml-example/
在本文中,我们将向您展示如何使用 YAML 来代替 Spring Boot 中的属性文件。
测试对象:
- Spring Boot 2.1.2 .版本
- maven3
- 蛇瓶:1.23
简而言之,在src/resources
文件夹中创建一个application.yml
,Spring Boot 会自动加载并解析.yml
文件,并将值绑定到标注有@ConfigurationProperties
的类中
不能使用@PropertySource
加载 P.S YAML 文件
1.YAML 和房地产
application.yml
logging:level:org.springframework: ERRORcom.mkyong: DEBUGspring:profiles:active: devmain:banner-mode: offemail: yaml@mkyong.com
thread-pool: 10wordpress:menus:- title: Homename: Homepath: /- title: Aboutname: Aboutpath: /aboutthemes:default-folder: /wp-content/themes/mkyongservers:- ip: 127.0.0.1path: /dev1- ip: 127.0.0.2path: /dev2- ip: 127.0.0.3path: /dev3
application.properties
# Spring Boot
logging.level.org.springframework=ERROR
logging.level.com.mkyong=DEBUG
spring.profiles.active=dev
spring.main.banner-mode=off# Global
email=properties@mkyong.com
thread-pool=10# WordPress
wordpress.menus[0].title=Home
wordpress.menus[0].name=Home
wordpress.menus[0].path=/
wordpress.menus[1].title=About
wordpress.menus[1].name=About
wordpress.menus[1].path=/about
wordpress.themes.default-folder=/wp-content/themes/mkyong
wordpress.servers[0].ip=127.0.0.1
wordpress.servers[0].path=/dev1
wordpress.servers[1].ip=127.0.0.2
wordpress.servers[1].path=/dev2
wordpress.servers[2].ip=127.0.0.3
wordpress.servers[2].path=/dev3
2.项目结构
3.项目依赖性
Spring Boot 使用 SnakeYAML 库解析 YAML 文件,SnakeYAML 库由spring-boot-starter
提供
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-yaml-example</artifactId><packaging>jar</packaging><name>Spring Boot YAML 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</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>
项目依赖关系:
+- 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-beans: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 <<------------- SnakeYAML
4.Spring Boot + YAML
4.1 Spring Boot 将加载并解析 YAML 文件,并将值绑定到下面的@ConfigurationProperties
类中。
GlobalProperties.java
package com.mkyong.config;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component
@ConfigurationProperties // no prefix, root level.
public class GlobalProperties {//thread-pool , relax bindingprivate int threadPool;private String email;//... getters and setters, toString()
}
WordPressProperties.java
package com.mkyong.config;import com.mkyong.config.model.Menu;
import com.mkyong.config.model.Server;
import com.mkyong.config.model.Theme;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;@Component
@ConfigurationProperties("wordpress")
public class WordPressProperties {private List<Menu> menus = new ArrayList<>();private Theme themes;private List<Server> servers = new ArrayList<>();//... getters and setters, toString()
}
4.2 模型,没什么特别的,就是一些标准类。
Menu.java
package com.mkyong.config.model;public class Menu {private String name;private String path;private String title;//... getters and setters, toString()
}
Server.java
package com.mkyong.config.model;public class Server {private String ip;private String path;//... getters and setters, toString()
}
Theme.java
package com.mkyong.config.model;public class Theme {private String defaultFolder;//... getters and setters, toString()
}
4.3 正常启动 Spring Boot,并打印出数值。
Application.java
package com.mkyong;import com.mkyong.config.GlobalProperties;
import com.mkyong.config.WordpressProperties;
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 WordPressProperties wpProperties;@Autowiredprivate GlobalProperties globalProperties;public static void main(String[] args) {SpringApplication.run(Application.class, args);}@Overridepublic void run(String... args) {System.out.println(globalProperties);System.out.println(wpProperties);}
}
5.演示
打包并运行它。
# run spring boot directly
$ mvn spring-boot:run# or package and run it
$ mvn package
$ java -jar target/spring-boot-yaml-example-1.0.jar
输出
GlobalProperties{threadPool=10, email='properties@mkyong.com'
}WordpressProperties{menus=[Menu{name='Home', path='/', title='Home'}, Menu{name='About', path='/about', title='About'}], themes=Theme{defaultFolder='/wp-content/themes/mkyong'}, servers=[Server{ip='127.0.0.1', path='/dev1'}, Server{ip='127.0.0.2', path='/dev2'}, Server{ip='127.0.0.3', path='/dev3'}]
}
YAML Multi-Profiles
Refer to this Spring Boot + Multiple Profiles YAML example
下载源代码
$ git clone https://github.com/mkyong/spring-boot.git
$ cd yaml-simple
$ mvn spring-boot:run
参考
- YAML
- 维基百科-YAML
- SnakeYAML
- 使用 YAML 代替属性
- Spring Boot @配置属性示例
Spring 集合(列表、集合、映射和属性)示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-collections-list-set-map-and-properties-example/
Spring 示例向您展示了如何将值注入集合类型(列表、集合、映射和属性)。支持 4 种主要集合类型:
- 列表—
- 设置-
- 地图—
- 属性—
春豆
一个客户对象,具有四个集合属性。
package com.mkyong.common;import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;public class Customer
{private List<Object> lists;private Set<Object> sets;private Map<Object, Object> maps;private Properties pros;//...
}
查看不同的代码片段以在 bean 配置文件中声明集合。
1.列表示例
<property name="lists"><list><value>1</value><ref bean="PersonBean" /><bean class="com.mkyong.common.Person"><property name="name" value="mkyongList" /><property name="address" value="address" /><property name="age" value="28" /></bean></list></property>
2.树立榜样
<property name="sets"><set><value>1</value><ref bean="PersonBean" /><bean class="com.mkyong.common.Person"><property name="name" value="mkyongSet" /><property name="address" value="address" /><property name="age" value="28" /></bean></set></property>
3.地图示例
<property name="maps"><map><entry key="Key 1" value="1" /><entry key="Key 2" value-ref="PersonBean" /><entry key="Key 3"><bean class="com.mkyong.common.Person"><property name="name" value="mkyongMap" /><property name="address" value="address" /><property name="age" value="28" /></bean></entry></map></property>
4.属性示例
<property name="pros"><props><prop key="admin">admin@nospam.com</prop><prop key="support">support@nospam.com</prop></props></property>
完整的 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 id="CustomerBean" class="com.mkyong.common.Customer"><!-- java.util.List --><property name="lists"><list><value>1</value><ref bean="PersonBean" /><bean class="com.mkyong.common.Person"><property name="name" value="mkyongList" /><property name="address" value="address" /><property name="age" value="28" /></bean></list></property><!-- java.util.Set --><property name="sets"><set><value>1</value><ref bean="PersonBean" /><bean class="com.mkyong.common.Person"><property name="name" value="mkyongSet" /><property name="address" value="address" /><property name="age" value="28" /></bean></set></property><!-- java.util.Map --><property name="maps"><map><entry key="Key 1" value="1" /><entry key="Key 2" value-ref="PersonBean" /><entry key="Key 3"><bean class="com.mkyong.common.Person"><property name="name" value="mkyongMap" /><property name="address" value="address" /><property name="age" value="28" /></bean></entry></map></property><!-- java.util.Properties --><property name="pros"><props><prop key="admin">admin@nospam.com</prop><prop key="support">support@nospam.com</prop></props></property></bean><bean id="PersonBean" class="com.mkyong.common.Person"><property name="name" value="mkyong1" /><property name="address" value="address 1" /><property name="age" value="28" /></bean></beans>
运行它…
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("SpringBeans.xml");Customer cust = (Customer)context.getBean("CustomerBean");System.out.println(cust);}
}
输出
Customer [lists=[
1,
Person [address=address 1, age=28, name=mkyong1],
Person [address=address, age=28, name=mkyongList]
], maps={
key 1=1,
key 2=Person [address=address 1, age=28, name=mkyong1],
key 3=Person [address=address, age=28, name=mkyongMap]
}, pros={admin=admin@nospam.com, support=support@nospam.com}, sets=[
1,
Person [address=address 1, age=28, name=mkyong1],
Person [address=address, age=28, name=mkyongSet]]
]
下载源代码
Download it – Spring-Collection-Example.zip (6 KB)spring
Spring 数据 MongoDB–自动序列 ID 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/mongodb/spring-data-mongodb-auto-sequence-id-example/
在本教程中,我们将向您展示如何在 MongoDB + Spring 数据环境中生成一个自动递增的序列 id。
本项目中使用的工具:
- Spring Data MongoDB 1.2.1.RELEASE
- MongoDB 2.4.5
- Eclipse 4.2
- maven3
在本教程结束时,如果保存了集合名称“hosting ”,将会分配一个新的自动递增序列 id。下面是生成序列 id 的 Java 代码片段。
public long getNextSequenceId(String key) {Query query = new Query(Criteria.where("_id").is(key));Update update = new Update();update.inc("seq", 1);FindAndModifyOptions options = new FindAndModifyOptions();options.returnNew(true);SequenceId seqId = mongoOperation.findAndModify(query, update, options, SequenceId.class);return seqId.getSeq();}
1.项目结构
查看项目目录结构,这是一个标准的 Maven 项目。
## 2.Maven Pom
如果您对项目依赖关系感兴趣。
pom.xml
<project ...><properties><jdk.version>1.6</jdk.version><spring.version>3.2.2.RELEASE</spring.version><mongojavadriver.version>2.11.1</mongojavadriver.version><springdata.version>1.2.1.RELEASE</springdata.version></properties><dependencies><!-- Spring Core --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><!-- need this for @Configuration --><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2.2</version></dependency><!-- Spring Data for MongoDB --><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-mongodb</artifactId><version>${springdata.version}</version></dependency><!-- Java MongoDB Driver --><dependency><groupId>org.mongodb</groupId><artifactId>mongo-java-driver</artifactId><version>${mongojavadriver.version}</version></dependency></dependencies><build><finalName>SpringData</finalName><plugins><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.序列集合
我们创建一个名为“sequence”的集合来存储自动增加的序列 id。参考下面的SequenceDaoImpl.java
,它显示了生成序列 id 的代码。
Note
Create the “sequence” collection in your MongoDB first!
db.sequence.insert({_id: "hosting",seq: 0})
SequenceId.java
package com.mkyong.seq.model;import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;@Document(collection = "sequence")
public class SequenceId {@Idprivate String id;private long seq;//get, set, toString...
}
SequenceDao.java
package com.mkyong.seq.dao;import com.mkyong.seq.exception.SequenceException;public interface SequenceDao {long getNextSequenceId(String key) throws SequenceException;}
SequenceDaoImpl.java
package com.mkyong.seq.dao;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;import com.mkyong.seq.exception.SequenceException;
import com.mkyong.seq.model.SequenceId;@Repository
public class SequenceDaoImpl implements SequenceDao {@Autowiredprivate MongoOperations mongoOperation;@Overridepublic long getNextSequenceId(String key) throws SequenceException {//get sequence idQuery query = new Query(Criteria.where("_id").is(key));//increase sequence id by 1Update update = new Update();update.inc("seq", 1);//return new increased idFindAndModifyOptions options = new FindAndModifyOptions();options.returnNew(true);//this is the magic happened.SequenceId seqId = mongoOperation.findAndModify(query, update, options, SequenceId.class);//if no id, throws SequenceException//optional, just a way to tell user when the sequence id is failed to generate.if (seqId == null) {throw new SequenceException("Unable to get sequence id for key : " + key);}return seqId.getSeq();}}
SequenceException.java
package com.mkyong.seq.exception;public class SequenceException extends RuntimeException {private static final long serialVersionUID = 1L;private String errCode;private String errMsg;//get, set...public SequenceException(String errMsg) {this.errMsg = errMsg;}}
4.获取序列 ID
为了获得序列 id,使用sequenceDao.getNextSequenceId("key")
。
HostingBo.java
package com.mkyong.hosting.bo;import com.mkyong.seq.exception.SequenceException;public interface HostingBo {void save(String name) throws SequenceException;}
HostingBoImpl.java
package com.mkyong.hosting.bo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import com.mkyong.hosting.dao.HostingDao;
import com.mkyong.hosting.model.Hosting;
import com.mkyong.seq.dao.SequenceDao;
import com.mkyong.seq.exception.SequenceException;@Service
public class HostingBoImpl implements HostingBo {private static final String HOSTING_SEQ_KEY = "hosting";@Autowiredprivate SequenceDao sequenceDao;@Autowiredprivate HostingDao hostingDao;@Overridepublic void save(String name) throws SequenceException {Hosting hosting = new Hosting();hosting.setId(sequenceDao.getNextSequenceId(HOSTING_SEQ_KEY));hosting.setName(name);hostingDao.save(hosting);System.out.println(hosting);}}
5.测试
运行一个简单的测试。
package com.mkyong;import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;import com.mkyong.config.AppConfig;
import com.mkyong.hosting.bo.HostingBo;
import com.mkyong.seq.exception.SequenceException;public class App {public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);HostingBo hostingBo = (HostingBo) ctx.getBean("hostingBoImpl");try {hostingBo.save("cloud.google.com");hostingBo.save("heroku.com");hostingBo.save("cloudbees.com");} catch (SequenceException e) {System.out.println(e.getErrMsg());}}
}
输出–Java 控制台
Hosting [id=1, name=cloud.google.com]
Hosting [id=2, name=heroku.com]
Hosting [id=3, name=cloudbees.com]
MongoDB 控制台。
>mongo> db.sequence.find()
{ "_id" : "hosting", "seq" : 3 }> db.hosting.find()
{ "_id" : NumberLong(1), "_class" : "com.mkyong.hosting.model.Hosting", "name" : "cloud.google.com" }
{ "_id" : NumberLong(2), "_class" : "com.mkyong.hosting.model.Hosting", "name" : "heroku.com" }
{ "_id" : NumberLong(3), "_class" : "com.mkyong.hosting.model.Hosting", "name" : "cloudbees.com" }
>
6.常见问题
q . sequence exception–无法获取密钥的序列 id:hosting?
A .记得创建“序列”集合!
db.sequence.insert({_id: "hosting",seq: 0})
下载源代码
Download – SpringData-Auto-Sequence-Example.zip (24 KB)
参考
- MongoDB–创建一个自动递增序列字段
sequence id spring-data
Spring Data MongoDB:删除文档
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/mongodb/spring-data-mongodb-delete-document/
在 MongoDB 的 Spring data 中,可以使用remove()
和findAndRemove()
从 MongoDB 中删除文档。
- remove()–删除单个或多个文档。
- 删除单个文档,并返回被删除的文档。
Common Mistake
Don’t use findAndRemove()
to perform a batch delete (remove multiple documents), only the first document that matches the query will be removed. Refer query4 below:
1.删除文档示例
查看完整的示例,了解 remove()和 findAndRemove()的用法。
package com.mkyong.core;import java.util.ArrayList;
import java.util.List;import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;import com.mkyong.config.SpringMongoConfig;
import com.mkyong.model.User;/*** Delete example* * @author mkyong* */public class DeleteApp {public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringMongoConfig.class);MongoOperations mongoOperation = (MongoOperations) ctx.getBean("mongoTemplate");// insert 6 users for testingList<User> users = new ArrayList<User>();User user1 = new User("1001", "ant", 10);User user2 = new User("1002", "bird", 20);User user3 = new User("1003", "cat", 30);User user4 = new User("1004", "dog", 40);User user5 = new User("1005", "elephant", 50);User user6 = new User("1006", "frog", 60);users.add(user1);users.add(user2);users.add(user3);users.add(user4);users.add(user5);users.add(user6);mongoOperation.insert(users, User.class);Query query1 = new Query();query1.addCriteria(Criteria.where("name").exists(true).orOperator(Criteria.where("name").is("frog"), Criteria.where("name").is("dog")));mongoOperation.remove(query1, User.class);Query query2 = new Query();query2.addCriteria(Criteria.where("name").is("bird"));User userTest2 = mongoOperation.findOne(query2, User.class);mongoOperation.remove(userTest2);// The first document that matches the query is returned and also// removed from the collection in the database.Query query3 = new Query();query3.addCriteria(Criteria.where("name").is("ant"));User userTest3 = mongoOperation.findAndRemove(query3, User.class);System.out.println("Deleted document : " + userTest3);// either cat or elephant is deleted only, // common mistake, don't use for batch delete./*Query query4 = new Query(); query4.addCriteria(Criteria.where("name") .exists(true).orOperator(Criteria.where("name").is("cat"),Criteria.where("name").is("elephant")));mongoOperation.findAndRemove(query4, User.class);System.out.println("Deleted document : " + userTest4);*/System.out.println("\nAll users : ");List<User> allUsers = mongoOperation.findAll(User.class);for (User user : allUsers) {System.out.println(user);}mongoOperation.dropCollection(User.class);}}
输出
Deleted document : User [id=5162e0153004c3cb0a907370, ic=1001, name=ant, age=10]All users :
User [id=5162e0153004c3cb0a907372, ic=1003, name=cat, age=30]
User [id=5162e0153004c3cb0a907374, ic=1005, name=elephant, age=50]
下载源代码
Download it – SpringMongoDB-Delete-Example.zip (24 KB) ## 参考
- 从 MongoDB 中保存、更新和删除文档
- Java MongoDB 删除示例/
delete mongodb spring-data
Spring 数据 MongoDB hello world 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/mongodb/spring-data-mongodb-hello-world-example/
在本教程中,我们将向您展示如何使用" SpringData for MongoDB "框架,通过 Spring 的注释和 XML schema 在 MongoDB 中执行 CRUD 操作。
Updated on 1/04/2013
Article is updated to use latest SpringData v 1.2.0.RELEASE, it was v1.0.0.M2.
使用的工具和技术:
- spring Data MongoDB–1 . 2 . 0 . release
- 弹簧芯–3 . 2 . 2 .释放
- Java Mongo 驱动程序–2 . 11 . 0
- eclipse–4.2
- jdk 1.6
- maven–3 . 0 . 3
P.S Spring 数据要求 JDK 6.0 及以上,Spring Framework 3.0.x 及以上。
1.项目结构
一个经典的 Maven 风格的 Java 项目目录结构。
2.属国
需要以下库:
spring-data-mongodb
Currently, the “spring-data-mongodb
” jar is only available in “http://maven.springframework.org/milestone“, so, you have to declare this repository also.
更新于 2012 年 13 月 9 日
spring-data-mongodb
在 Maven 中央存储库中可用,不再需要 Spring 存储库。
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.core</groupId><artifactId>SpringMongoDBExample</artifactId><packaging>jar</packaging><version>1.0</version><name>SpringMongoExample</name><url>http://maven.apache.org</url><dependencies><!-- Spring framework --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>3.2.2.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>3.2.2.RELEASE</version></dependency><!-- mongodb java driver --><dependency><groupId>org.mongodb</groupId><artifactId>mongo-java-driver</artifactId><version>2.11.0</version></dependency><!-- Spring data mongodb --><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-mongodb</artifactId><version>1.2.0.RELEASE</version></dependency><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2.2</version></dependency></dependencies><build><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><version>3.0</version><configuration><source>1.6</source><target>1.6</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-eclipse-plugin</artifactId><version>2.9</version><configuration><downloadSources>true</downloadSources><downloadJavadocs>true</downloadJavadocs></configuration></plugin></plugins></build></project>
3.Spring 配置、注释和 XML
在这里,我们向您展示了两种配置 Spring 数据和连接到 MongoDB 的方法,分别是通过注释和 XML schema。
Note
Refer to this official reference Connecting to MongoDB with Spring.
3.1 注释
扩展了AbstractMongoConfiguration
是最快的方式,它有助于配置你需要启动的一切,像mongoTemplate
对象。
SpringMongoConfig.java
package com.mkyong.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;import com.mongodb.Mongo;
import com.mongodb.MongoClient;@Configuration
public class SpringMongoConfig extends AbstractMongoConfiguration {@Overridepublic String getDatabaseName() {return "yourdb";}@Override@Beanpublic Mongo mongo() throws Exception {return new MongoClient("127.0.0.1");}
}
或者,我更喜欢这个,更灵活地配置一切。
SpringMongoConfig1.java
package com.mkyong.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;import com.mongodb.MongoClient;@Configuration
public class SpringMongoConfig1 {public @BeanMongoDbFactory mongoDbFactory() throws Exception {return new SimpleMongoDbFactory(new MongoClient(), "yourdb");}public @BeanMongoTemplate mongoTemplate() throws Exception {MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory());return mongoTemplate;}}
并载入AnnotationConfigApplicationContext
:
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringMongoConfig.class);MongoOperations mongoOperation = (MongoOperations)ctx.getBean("mongoTemplate");
3.2 XML 模式
SpringConfig.xml
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:mongo="http://www.springframework.org/schema/data/mongo"xsi:schemaLocation="http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/data/mongohttp://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><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>
并将其包含在 Spring 的GenericXmlApplicationContext
:
ApplicationContext ctx = new GenericXmlApplicationContext("SpringConfig.xml");MongoOperations mongoOperation = (MongoOperations)ctx.getBean("mongoTemplate");
So, XML or Annotation?
Actually, both are doing the same thing, it’s just based on personal preferences. Personally, I like XML to configure things.
4.用户模型
一个用户对象,annotated @ Document——保存哪个集合。稍后,我们将向您展示如何使用 Spring 数据将该对象绑定到 MongoDB 或从 MongoDB 绑定。
User.java
package com.mkyong.model;import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;@Document(collection = "users")
public class User {@Idprivate String id;String username;String password;//getter, setter, toString, Constructors}
5.演示–CRUD 操作
完整的示例向您展示了如何使用 Spring 数据在 MongoDB 中执行 CRUD 操作。Spring 数据 API 非常简洁,应该是不言自明的。
App.java
package com.mkyong.core;import java.util.List;import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;import com.mkyong.config.SpringMongoConfig;
import com.mkyong.model.User;
//import org.springframework.context.support.GenericXmlApplicationContext;public class App {public static void main(String[] args) {// For XML//ApplicationContext ctx = new GenericXmlApplicationContext("SpringConfig.xml");// For AnnotationApplicationContext ctx = new AnnotationConfigApplicationContext(SpringMongoConfig.class);MongoOperations mongoOperation = (MongoOperations) ctx.getBean("mongoTemplate");User user = new User("mkyong", "password123");// savemongoOperation.save(user);// now user object got the created id.System.out.println("1\. user : " + user);// query to search userQuery searchUserQuery = new Query(Criteria.where("username").is("mkyong"));// find the saved user again.User savedUser = mongoOperation.findOne(searchUserQuery, User.class);System.out.println("2\. find - savedUser : " + savedUser);// update passwordmongoOperation.updateFirst(searchUserQuery, Update.update("password", "new password"),User.class);// find the updated user objectUser updatedUser = mongoOperation.findOne(searchUserQuery, User.class);System.out.println("3\. updatedUser : " + updatedUser);// deletemongoOperation.remove(searchUserQuery, User.class);// List, it should be empty now.List<User> listUser = mongoOperation.findAll(User.class);System.out.println("4\. Number of user = " + listUser.size());}}
输出
1\. user : User [id=516627653004953049d9ddf0, username=mkyong, password=password123]
2\. find - savedUser : User [id=516627653004953049d9ddf0, username=mkyong, password=password123]
3\. updatedUser : User [id=516627653004953049d9ddf0, username=mkyong, password=new password]
4\. Number of user = 0
下载源代码
Download it – SpringMongoDB-HelloWorld-Example.zip (24 KB)
参考
- 【MongoDB 的春季数据
- 用 Spring 连接到 MongoDB】
- 奥雷利春天数据 mongodb 教程
- 又一个好的春季数据 mongodb 教程
Tags : hello world mongodb spring-data
相关文章
-
由于基础科目的限制,你不能
-
Spring Data MongoDB:插入文档
-
Spring Data MongoDB:更新文档
-
Spring Data MongoDB:查询文档
-
Spring Data MongoDB:删除文档
-
MongoDB hello world 示例
-
Spring Data MongoDB:保存二进制文件,GridFS exa
-
Spring Data MongoDB remove _ class 列
-
Spring Data MongoDB:获取最后修改的记录(d
-
Spring Data MongoDB -选择要返回的字段
Spring Data MongoDB:插入文档
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/mongodb/spring-data-mongodb-insert-document/
在 Spring data MongoDB 中,可以使用save()
、insert()
将一个或一列对象保存到 MongoDB 数据库中。
User user = new User("...");//save user object into "user" collection / table//class name will be used as collection namemongoOperation.save(user);//save user object into "tableA" collectionmongoOperation.save(user,"tableA");//insert user object into "user" collection//class name will be used as collection namemongoOperation.insert(user);//insert user object into "tableA" collectionmongoOperation.insert(user, "tableA");//insert a list of user objectsmongoOperation.insert(listofUser);
默认情况下,如果你保存了一个对象,并且没有指定任何“集合名”,类名将被用作集合名。
1.保存并插入
你应该使用保存还是插入?
- 保存–应该重命名为
saveOrUpdate()
,如果“_id”不存在,则执行insert()
,如果“_id”存在,则执行update()
。 - insert–仅插入,如果存在“_id ”,则产生错误。
参见下面的例子
//get an existed data, and update itUser userD1 = mongoOperation.findOne(new Query(Criteria.where("age").is(64)), User.class);userD1.setName("new name");userD1.setAge(100);//if you insert it, 'E11000 duplicate key error index' error is generated.//mongoOperation.insert(userD1); //instead you should use save.mongoOperation.save(userD1);
2.插入文档示例
查看一个完整的示例,向您展示如何将一个或一个“用户”对象列表保存到 MongoDB 中。
SpringMongoConfig.java – Create a mongoTemplate bean in Spring container.
package com.mkyong.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;
import com.mongodb.MongoClient;/*** Spring MongoDB configuration file* */
@Configuration
public class SpringMongoConfig{public @BeanMongoTemplate mongoTemplate() throws Exception {MongoTemplate mongoTemplate = new MongoTemplate(new MongoClient("127.0.0.1"),"yourdb");return mongoTemplate;}}
当您保存该对象时,使用@Document 定义一个“集合名称”。在这种情况下,当“用户”对象保存时,它将保存到“用户”集合中。
User.java
package com.mkyong.user;import java.util.Date;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;@Document(collection = "users")
public class User {@Idprivate String id;@Indexedprivate String ic;private String name;private int age;@DateTimeFormat(iso = ISO.DATE_TIME)private Date createdDate;//getter and setter methods
}
完整的例子,向您展示不同的方式插入数据,阅读代码和注释,不言自明。
App.java
package com.mkyong.core;import java.util.ArrayList;
import java.util.Date;
import java.util.List;import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;import com.mkyong.config.SpringMongoConfig;
import com.mkyong.user.User;public class App {public static void main(String[] args) {// For AnnotationApplicationContext ctx = new AnnotationConfigApplicationContext(SpringMongoConfig.class);MongoOperations mongoOperation = (MongoOperations) ctx.getBean("mongoTemplate");// Case1 - insert a user, put "tableA" as collection nameSystem.out.println("Case 1...");User userA = new User("1000", "apple", 54, new Date());mongoOperation.save(userA, "tableA");// findQuery findUserQuery = new Query();findUserQuery.addCriteria(Criteria.where("ic").is("1000"));User userA1 = mongoOperation.findOne(findUserQuery, User.class, "tableA");System.out.println(userA1);// Case2 - insert a user, put entity as collection nameSystem.out.println("Case 2...");User userB = new User("2000", "orange", 64, new Date());mongoOperation.save(userB);// findUser userB1 = mongoOperation.findOne(new Query(Criteria.where("age").is(64)), User.class);System.out.println(userB1);// Case3 - insert a list of usersSystem.out.println("Case 3...");User userC = new User("3000", "metallica", 34, new Date());User userD = new User("4000", "metallica", 34, new Date());User userE = new User("5000", "metallica", 34, new Date());List<User> userList = new ArrayList<User>();userList.add(userC);userList.add(userD);userList.add(userE);mongoOperation.insert(userList, User.class);// findList<User> users = mongoOperation.find(new Query(Criteria.where("name").is("metallica")),User.class);for (User temp : users) {System.out.println(temp);}//save vs insertSystem.out.println("Case 4...");User userD1 = mongoOperation.findOne(new Query(Criteria.where("age").is(64)), User.class);userD1.setName("new name");userD1.setAge(100);//E11000 duplicate key error index, _id existed//mongoOperation.insert(userD1); mongoOperation.save(userD1);User userE1 = mongoOperation.findOne(new Query(Criteria.where("age").is(100)), User.class);System.out.println(userE1);}}
输出
Case 1...
User [id=id, ic=1000, name=apple, age=54, createdDate=Sat Apr 06 12:35:15 MYT 2013]
Case 2...
User [id=id, ic=2000, name=orange, age=64, createdDate=Sat Apr 06 12:59:19 MYT 2013]
Case 3...
User [id=id, ic=3000, name=metallica, age=34, createdDate=Sat Apr 06 12:59:19 MYT 2013]
User [id=id, ic=4000, name=metallica, age=34, createdDate=Sat Apr 06 12:59:19 MYT 2013]
User [id=id, ic=5000, name=metallica, age=34, createdDate=Sat Apr 06 12:59:19 MYT 2013]
Case 4...
User [id=id, ic=2000, name=new name, age=100, createdDate=Sat Apr 06 12:59:19 MYT 2013]
3.Mongo 控制台
查看 Mongo 控制台,看看插入和创建了什么。
> mongo
MongoDB shell version: 2.2.3
connecting to: test> show dbs
admin 0.203125GB
yourdb 0.203125GB> use yourdb
switched to db yourdb
> show collections
system.indexes
tableA
users> db.tableA.find()
{ "_id" : ObjectId("id"), "_class" : "com.mkyong.user.User",
"ic" : "1000", "name" : "apple", "age" : 54, "createdDate" : ISODate("2013-04-06T05:04:06.384Z") }> db.users.find()
{ "_id" : ObjectId("id"), "_class" : "com.mkyong.user.User",
"ic" : "3000", "name" : "metallica", "age" : 34, "createdDate" : ISODate("2013-04-06T05:04:06.735Z") }
{ "_id" : ObjectId("id"), "_class" : "com.mkyong.user.User",
"ic" : "4000", "name" : "metallica", "age" : 34, "createdDate" : ISODate("2013-04-06T05:04:06.735Z") }
{ "_id" : ObjectId("id"), "_class" : "com.mkyong.user.User",
"ic" : "5000", "name" : "metallica", "age" : 34, "createdDate" : ISODate("2013-04-06T05:04:06.735Z") }
{ "_id" : ObjectId("id"), "_class" : "com.mkyong.user.User",
"ic" : "2000", "name" : "new name", "age" : 100, "createdDate" : ISODate("2013-04-06T05:04:06.731Z") }
页(page 的缩写)s 要移除 extra _class 列,请阅读本文—Spring Data MongoDB Remove _ class 列。
下载源代码
Download it – SpringData-MongoDB-Insert-Example.zip (24KB)
参考
- Spring Data MongoDB–保存、更新和删除文档
- 春季数据 MongoDB Hello World 示例
Spring Data MongoDB:查询文档
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/mongodb/spring-data-mongodb-query-document/
在这里,我们向您展示了一些从 MongoDB 查询文档的例子,使用了 query、Criteria 和一些常见的操作符。
测试数据
> db.users.find()
{ "_id" : ObjectId("id"), "ic" : "1001", "name" : "ant", "age" : 10 }
{ "_id" : ObjectId("id"), "ic" : "1002", "name" : "bird", "age" : 20 }
{ "_id" : ObjectId("id"), "ic" : "1003", "name" : "cat", "age" : 30 }
{ "_id" : ObjectId("id"), "ic" : "1004", "name" : "dog", "age" : 40 }
{ "_id" : ObjectId("id"), "ic" : "1005", "name" : "elephant", "age" : 50 }
{ "_id" : ObjectId("id"), "ic" : "1006", "name" : "frog", "age" : 60 }
注:本例在mongo-java-driver-2.11.0.jar
和spring-data-mongodb-1.2.0.RELEASE.jar
和下测试
1.基本查询示例
如果您熟悉核心 MongoDB 控制台 find()命令,只需将“原始”查询放在BasicQuery
中。
BasicQuery query1 = new BasicQuery("{ age : { $lt : 40 }, name : 'cat' }");
User userTest1 = mongoOperation.findOne(query1, User.class);System.out.println("query1 - " + query1.toString());
System.out.println("userTest1 - " + userTest1);
输出
query1 - Query: { "age" : { "$lt" : 40} , "name" : "cat"}, Fields: null, Sort: { }
userTest1 - User [id=id, ic=1003, name=cat, age=30]
2.找一个例子
findOne 将返回与查询匹配的单个文档,您可以用Criteria.and()
方法组合几个标准。更多细节见例 4。
Query query2 = new Query();
query2.addCriteria(Criteria.where("name").is("dog").and("age").is(40));User userTest2 = mongoOperation.findOne(query2, User.class);
System.out.println("query2 - " + query2.toString());
System.out.println("userTest2 - " + userTest2);
输出
query2 - Query: { "name" : "dog" , "age" : 40}, Fields: null, Sort: null
userTest2 - User [id=id, ic=1004, name=dog, age=40]
3.查找和$inc 示例
查找并返回与查询匹配的文档列表。这个例子也展示了$inc
操作符的使用。
List<Integer> listOfAge = new ArrayList<Integer>();
listOfAge.add(10);
listOfAge.add(30);
listOfAge.add(40);Query query3 = new Query();
query3.addCriteria(Criteria.where("age").in(listOfAge));List<User> userTest3 = mongoOperation.find(query3, User.class);
System.out.println("query3 - " + query3.toString());for (User user : userTest3) {System.out.println("userTest3 - " + user);
}
输出
query3 - Query: { "age" : { "$in" : [ 10 , 30 , 40]}}, Fields: null, Sort: null
userTest3 - User [id=id, ic=1001, name=ant, age=10]
userTest3 - User [id=id, ic=1003, name=cat, age=30]
userTest3 - User [id=id, ic=1004, name=dog, age=40]
4.查找和\(gt,\)lt,$和示例
查找并返回与查询匹配的文档列表。这个例子还展示了$gt
、$lt
和$and
操作符的使用。
Query query4 = new Query();
query4.addCriteria(Criteria.where("age").lt(40).and("age").gt(10));List<User> userTest4 = mongoOperation.find(query4, User.class);
System.out.println("query4 - " + query4.toString());for (User user : userTest4) {System.out.println("userTest4 - " + user);
}
Oppss,生成一个错误消息,API 不这样工作:)
Due to limitations of the com.mongodb.BasicDBObject, you can't add a second 'age' expression
specified as 'age : { "$gt" : 10}'. Criteria already contains 'age : { "$lt" : 40}'.
您不能使用Criteria.and()
将多个标准添加到同一个字段中,要解决这个问题,请使用Criteria.andOperator()
,参见更新的示例:
Query query4 = new Query();
query4.addCriteria(Criteria.where("age").exists(true).andOperator(Criteria.where("age").gt(10),Criteria.where("age").lt(40))
);List<User> userTest4 = mongoOperation.find(query4, User.class);
System.out.println("query4 - " + query4.toString());for (User user : userTest4) {System.out.println("userTest4 - " + user);
}
输出
query4 - Query: { "age" : { "$lt" : 40} , "$and" : [ { "age" : { "$gt" : 10}}]}, Fields: null, Sort: null
userTest4 - User [id=51627a0a3004cc5c0af72964, ic=1002, name=bird, age=20]
userTest4 - User [id=51627a0a3004cc5c0af72965, ic=1003, name=cat, age=30]
5.查找和排序示例
查找并排序结果。
Query query5 = new Query();
query5.addCriteria(Criteria.where("age").gte(30));
query5.with(new Sort(Sort.Direction.DESC, "age"));List<User> userTest5 = mongoOperation.find(query5, User.class);
System.out.println("query5 - " + query5.toString());for (User user : userTest5) {System.out.println("userTest5 - " + user);
}
输出
query5 - Query: { "age" : { "$gte" : 30}}, Fields: null, Sort: { "age" : -1}
userTest5 - User [id=id, ic=1006, name=frog, age=60]
userTest5 - User [id=id, ic=1005, name=elephant, age=50]
userTest5 - User [id=id, ic=1004, name=dog, age=40]
userTest5 - User [id=id, ic=1003, name=cat, age=30]
6.find 和$regex 示例
通过正则表达式模式查找。
Query query6 = new Query();
query6.addCriteria(Criteria.where("name").regex("D.*G", "i"));List<User> userTest6 = mongoOperation.find(query6, User.class);
System.out.println("query6 - " + query6.toString());for (User user : userTest6) {System.out.println("userTest6 - " + user);
}
输出
query6 - Query: { "name" : { "$regex" : "D.*G" , "$options" : "i"}}, Fields: null, Sort: null
userTest6 - User [id=id, ic=1004, name=dog, age=40]
7.完整示例
一个完整的例子,结合了例 1 到例 6 中的所有内容。
SpringMongoConfig.java
package com.mkyong.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;import com.mongodb.MongoClient;/*** Spring MongoDB configuration file* */
@Configuration
public class SpringMongoConfig{public @BeanMongoTemplate mongoTemplate() throws Exception {MongoTemplate mongoTemplate = new MongoTemplate(new MongoClient("127.0.0.1"),"yourdb");return mongoTemplate;}}
User.java
package com.mkyong.model;import java.util.Date;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;@Document(collection = "users")
public class User {@Idprivate String id;@Indexedprivate String ic;private String name; private int age;//getter, setter and constructor methods}
QueryApp.java
package com.mkyong.core;import java.util.ArrayList;
import java.util.List;import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;import com.mkyong.config.SpringMongoConfig;
import com.mkyong.model.User;/*** Query example* * @author mkyong* */
public class QueryApp {public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringMongoConfig.class);MongoOperations mongoOperation = (MongoOperations) ctx.getBean("mongoTemplate");// insert 6 users for testingList<User> users = new ArrayList<User>();User user1 = new User("1001", "ant", 10);User user2 = new User("1002", "bird", 20);User user3 = new User("1003", "cat", 30);User user4 = new User("1004", "dog", 40);User user5 = new User("1005", "elephant",50);User user6 = new User("1006", "frog", 60);users.add(user1);users.add(user2);users.add(user3);users.add(user4);users.add(user5);users.add(user6);mongoOperation.insert(users, User.class);System.out.println("Case 1 - find with BasicQuery example");BasicQuery query1 = new BasicQuery("{ age : { $lt : 40 }, name : 'cat' }");User userTest1 = mongoOperation.findOne(query1, User.class);System.out.println("query1 - " + query1.toString());System.out.println("userTest1 - " + userTest1);System.out.println("\nCase 2 - find example");Query query2 = new Query();query2.addCriteria(Criteria.where("name").is("dog").and("age").is(40));User userTest2 = mongoOperation.findOne(query2, User.class);System.out.println("query2 - " + query2.toString());System.out.println("userTest2 - " + userTest2);System.out.println("\nCase 3 - find list $inc example");List<Integer> listOfAge = new ArrayList<Integer>();listOfAge.add(10);listOfAge.add(30);listOfAge.add(40);Query query3 = new Query();query3.addCriteria(Criteria.where("age").in(listOfAge));List<User> userTest3 = mongoOperation.find(query3, User.class);System.out.println("query3 - " + query3.toString());for (User user : userTest3) {System.out.println("userTest3 - " + user);}System.out.println("\nCase 4 - find list $and $lt, $gt example");Query query4 = new Query();// it hits error// query4.addCriteria(Criteria.where("age").lt(40).and("age").gt(10));query4.addCriteria(Criteria.where("age").exists(true).andOperator(Criteria.where("age").gt(10),Criteria.where("age").lt(40)));List<User> userTest4 = mongoOperation.find(query4, User.class);System.out.println("query4 - " + query4.toString());for (User user : userTest4) {System.out.println("userTest4 - " + user);}System.out.println("\nCase 5 - find list and sorting example");Query query5 = new Query();query5.addCriteria(Criteria.where("age").gte(30));query5.with(new Sort(Sort.Direction.DESC, "age"));List<User> userTest5 = mongoOperation.find(query5, User.class);System.out.println("query5 - " + query5.toString());for (User user : userTest5) {System.out.println("userTest5 - " + user);}System.out.println("\nCase 6 - find by regex example");Query query6 = new Query();query6.addCriteria(Criteria.where("name").regex("D.*G", "i"));List<User> userTest6 = mongoOperation.find(query6, User.class);System.out.println("query6 - " + query6.toString());for (User user : userTest6) {System.out.println("userTest6 - " + user);}mongoOperation.dropCollection(User.class);}}
输出
Case 1 - find with BasicQuery example
query1 - Query: { "age" : { "$lt" : 40} , "name" : "cat"}, Fields: null, Sort: { }
userTest1 - User [id=id, ic=1003, name=cat, age=30]Case 2 - find example
query2 - Query: { "name" : "dog" , "age" : 40}, Fields: null, Sort: null
userTest2 - User [id=id, ic=1004, name=dog, age=40]Case 3 - find list $inc example
query3 - Query: { "age" : { "$in" : [ 10 , 30 , 40]}}, Fields: null, Sort: null
userTest3 - User [id=id, ic=1001, name=ant, age=10]
userTest3 - User [id=id, ic=1003, name=cat, age=30]
userTest3 - User [id=id, ic=1004, name=dog, age=40]Case 4 - find list $and $lt, $gt example
query4 - Query: { "age" : { "$lt" : 40} , "$and" : [ { "age" : { "$gt" : 10}}]}, Fields: null, Sort: null
userTest4 - User [id=id, ic=1002, name=bird, age=20]
userTest4 - User [id=id, ic=1003, name=cat, age=30]Case 5 - find list and sorting example
query5 - Query: { "age" : { "$gte" : 30}}, Fields: null, Sort: { "age" : -1}
userTest5 - User [id=id, ic=1006, name=frog, age=60]
userTest5 - User [id=id, ic=1005, name=elephant, age=50]
userTest5 - User [id=id, ic=1004, name=dog, age=40]
userTest5 - User [id=id, ic=1003, name=cat, age=30]Case 6 - find by regex example
query6 - Query: { "name" : { "$regex" : "D.*G" , "$options" : "i"}}, Fields: null, Sort: null
userTest6 - User [id=id, ic=1004, name=dog, age=40]
下载源代码
Download it – SpringMongoDB-Query-Example.zip (25 KB)
参考
- Spring data Mongodb-查询文档
- Java MongoDB 查询示例/
mongodb query spring-data
Spring 数据 MongoDB remove _class 列
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/mongodb/spring-data-mongodb-remove-_class-column/
默认情况下,SpringData 的MappingMongoConverter
为 MongoDB 中保存的每个对象添加一个额外的“ _class ”列。举个例子,
public class User {String username;String password;//...getters and setters
}
保存
MongoOperations mongoOperation = (MongoOperations)ctx.getBean("mongoTemplate"); User user = new User("mkyong", "password123");mongoOperation.save(user, "users");
结果
> db.users.find()
{ "_class" : "com.mkyong.user.User", "_id" : ObjectId("5050aef830041f24ff2bd16e"), "password" : "new password", "username" : "mkyong"
}
由于一个原因,SpringData 创建了这个额外的 _class 。要删除这个额外的“_ 类,覆盖MappingMongoConverter
,并传递一个new DefaultMongoTypeMapper(null)
。
在这里,我们向您展示如何以注释或 XML 的方式删除 _class。
1.注释
@Configuration
public class SpringMongoConfig{public @BeanMongoDbFactory mongoDbFactory() throws Exception {return new SimpleMongoDbFactory(new Mongo(), "database");}public @BeanMongoTemplate mongoTemplate() throws Exception {//remove _classMappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext());converter.setTypeMapper(new DefaultMongoTypeMapper(null));MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);return mongoTemplate;}}
2.可扩展标记语言
同样的事情,但是在 XML 文件中。
<mongo:mongo host="localhost" port="27017" />
<mongo:db-factory dbname="database" /><bean id="mappingContext"class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" /><bean id="defaultMongoTypeMapper"class="org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper"><constructor-arg name="typeKey"><null/></constructor-arg></bean><bean id="mappingMongoConverter"class="org.springframework.data.mongodb.core.convert.MappingMongoConverter"><constructor-arg name="mongoDbFactory" ref="mongoDbFactory" /><constructor-arg name="mappingContext" ref="mappingContext" /><property name="typeMapper" ref="defaultMongoTypeMapper" /></bean><bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"><constructor-arg name="mongoDbFactory" ref="mongoDbFactory" /><constructor-arg name="mongoConverter" ref="mappingMongoConverter" /></bean>
3.再测试一次
再保存一次,“_class”就没了。
> db.users.find()
{ "_id" : ObjectId("random code"), "password" : "new password", "username" : "mkyong"
}
参考
- stack overflow–mapping mongo converter remove _ class
- 春季论坛–mapping mongoconverter remove _ class
mongodb spring-data
Spring 数据 MongoDB:保存二进制文件,GridFS 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/mongodb/spring-data-mongodb-save-binary-file-gridfs-example/
在 MongoDB 中,可以使用 GridFS 存储二进制文件。在本教程中,我们将向您展示如何使用 Spring Data 的GridFsTemplate
在 MongoDB 中存储/读取图像。
1.grid fs–保存示例(注释中的 Spring 配置)
获取一个图像文件并保存到 MongoDB 中。
SpringMongoConfig.java
package com.mkyong.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;import com.mongodb.Mongo;
import com.mongodb.MongoClient;/*** Spring MongoDB configuration file* */
@Configuration
public class SpringMongoConfig extends AbstractMongoConfiguration{@Beanpublic GridFsTemplate gridFsTemplate() throws Exception {return new GridFsTemplate(mongoDbFactory(), mappingMongoConverter());}@Overrideprotected String getDatabaseName() {return "yourdb";}@Override@Beanpublic Mongo mongo() throws Exception {return new MongoClient("127.0.0.1");}}
GridFsAppStore.java
package com.mkyong.core;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.mongodb.gridfs.GridFsOperations;import com.mkyong.config.SpringMongoConfig;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;/*** GridFs example* * @author mkyong* */public class GridFsAppStore {public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringMongoConfig.class);GridFsOperations gridOperations = (GridFsOperations) ctx.getBean("gridFsTemplate");DBObject metaData = new BasicDBObject();metaData.put("extra1", "anything 1");metaData.put("extra2", "anything 2");InputStream inputStream = null;try {inputStream = new FileInputStream("/Users/mkyong/Downloads/testing.png");gridOperations.store(inputStream, "testing.png", "image/png", metaData);} catch (FileNotFoundException e) {e.printStackTrace();} finally {if (inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}System.out.println("Done");}}
查看 MongoDB 控制台,看看保存了什么。
> show dbs
yourdb 0.203125GB> use yourdb
switched to db yourdb> show collections
fs.chunks
fs.files
system.indexes> db.fs.files.find()
{ "_id" : ObjectId("51641c5630045c9b3db35afc"), "chunkSize" : NumberLong(262144),
"length" : NumberLong(4238), "md5" : "9969527cd95a5a573f15e953f0036800", "filename" : "testing.png",
"contentType" : "image/png", "uploadDate" : ISODate("2013-04-09T13:49:10.104Z"),
"aliases" : null, "metadata" : { "extra1" : "anything 1", "extra2" : "anything 2" } }
>> db.fs.chunks.find()
{ "_id" : ObjectId("51641c5630045c9b3db35afd"),
"files_id" : ObjectId("51641c5630045c9b3db35afc"), "n" : 0,
"data" : BinData(0,"/9j/4AAQSkZJRgABAgAAZ......EQH/9k=") }
图像信息保存在fs.files
中,图像文件(二进制转换)保存在fs.chunks
中,通过_id
和files_id
链接。
2.grid fs–读取示例(XML 文件中的 Spring 配置)
从 MongoDB 中读取上面的图像文件,并将其保存为另一个图像。
SpringConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mongo="http://www.springframework.org/schema/data/mongo"xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><mongo:db-factory id="mongoDbFactory" dbname="yourdb" /><mongo:mapping-converter id="converter" /><bean name="gridFsTemplate"class="org.springframework.data.mongodb.gridfs.GridFsTemplate"><constructor-arg ref="mongoDbFactory" /><constructor-arg ref="converter" /></bean></beans>
GridFsAppStore.java
package com.mkyong.core;import java.io.IOException;
import java.util.List;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsOperations;import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.gridfs.GridFSDBFile;/*** GridFs example* * @author mkyong* */public class GridFsAppRead {public static void main(String[] args) {ApplicationContext ctx = new GenericXmlApplicationContext("SpringConfig.xml");GridFsOperations gridOperations = (GridFsOperations) ctx.getBean("gridFsTemplate");List<GridFSDBFile> result = gridOperations.find(new Query().addCriteria(Criteria.where("filename").is("testing.png")));for (GridFSDBFile file : result) {try {System.out.println(file.getFilename());System.out.println(file.getContentType());//save as another imagefile.writeTo("/Users/mkyong/Downloads/new-testing.png");} catch (IOException e) {e.printStackTrace();}}System.out.println("Done");}
}
下载源代码
Download it – SpringMongoDB-GridFs-Example.zip (24 KB)
参考
- AbstractMongoConfiguration JavaDoc
- Spring Data MongoDB GridFS 支持
- 春季数据 MongoDB Hello World 示例
- Java MongoDB:保存图像示例
binary data gridfs mongodb spring-data
Spring 数据 MongoDB:更新文档
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/mongodb/spring-data-mongodb-update-document/
在 Spring data-MongoDB 中,您可以使用以下方法来更新文档。
- 保存–更新整个对象,如果“_id”存在,则执行更新,否则插入它。
- update first–更新匹配查询的第一个文档。
- update multi–更新与查询匹配的所有文档。
- upserting–如果没有与查询匹配的文档,则通过组合查询和更新对象来创建新文档。
- findAndModify–与 updateMulti 相同,但是它有一个额外的选项,可以返回旧的或新更新的文档。
注:所有例子都在mongo-java-driver-2.11.0.jar
和spring-data-mongodb-1.2.0.RELEASE.jar
和下测试
1.saveourupdate–第 1 部分示例
假设下面 json 数据被插入 MongoDB。
{ "_id" : ObjectId("id"), "ic" : "1001", "name" : "appleA", "age" : 20, "createdDate" : ISODate("2013-04-06T23:17:35.530Z")
}
找到文档,用save()
方法修改更新。
Query query = new Query();query.addCriteria(Criteria.where("name").is("appleA"));User userTest1 = mongoOperation.findOne(query, User.class);System.out.println("userTest1 - " + userTest1);//modify and update with save()userTest1.setAge(99);mongoOperation.save(userTest1);//get the updated object againUser userTest1_1 = mongoOperation.findOne(query, User.class);System.out.println("userTest1_1 - " + userTest1_1);
输出
userTest1 - User [id=id, ic=1001, name=appleA, age=20, createdDate=Sat Apr 06 23:17:35 MYT 2013]
userTest1_1 - User [id=id, ic=1001, name=appleA, age=99, createdDate=Sat Apr 06 23:17:35 MYT 2013]
Note
See example 2, it shows a common mistake made by most of the developers. ## 2.saveourupdate–第 2 部分示例
这是一个失败的例子,仔细阅读,一个真正常见的错误。
假设下面 json 数据被插入 MongoDB。
{ "_id" : ObjectId("id"), "ic" : "1002", "name" : "appleB", "age" : 20, "createdDate" : ISODate("2013-04-06T15:22:34.530Z")
}
在Query
中,您得到的文档只返回了一个“name”字段值,这确实经常发生,以保存对象返回的大小。返回的“用户”对象在以下字段中具有空值:年龄、ic 和创建日期,如果您修改“年龄”字段并更新它,它将覆盖所有内容,而不是更新修改后的字段-“年龄”。
Query query = new Query();query.addCriteria(Criteria.where("name").is("appleB"));query.fields().include("name");User userTest2 = mongoOperation.findOne(query, User.class);System.out.println("userTest2 - " + userTest2);userTest2.setAge(99);mongoOperation.save(userTest2);// ooppss, you just override everything, it caused ic=null and// createdDate=nullQuery query1 = new Query();query1.addCriteria(Criteria.where("name").is("appleB"));User userTest2_1 = mongoOperation.findOne(query1, User.class);System.out.println("userTest2_1 - " + userTest2_1);
输出
userTest2 - User [id=51603dba3004d7fffc202391, ic=null, name=appleB, age=0, createdDate=null]
userTest2_1 - User [id=51603dba3004d7fffc202391, ic=null, name=appleB, age=99, createdDate=null]
在 save()之后,字段“age”被正确更新,但是 ic 和 createdDate 都被设置为 null,整个“user”对象被更新。若要更新单个字段/键值,请不要使用 save(),而是使用 updateFirst()或 updateMulti()。
3.updateFirst 示例
更新匹配查询的第一个文档。在这种情况下,只有单个字段“年龄”被更新。
{ "_id" : ObjectId("id"), "ic" : "1003", "name" : "appleC", "age" : 20, "createdDate" : ISODate("2013-04-06T23:22:34.530Z")
}
//returns only 'name' fieldQuery query = new Query();query.addCriteria(Criteria.where("name").is("appleC"));query.fields().include("name");User userTest3 = mongoOperation.findOne(query, User.class);System.out.println("userTest3 - " + userTest3);Update update = new Update();update.set("age", 100);mongoOperation.updateFirst(query, update, User.class);//returns everythingQuery query1 = new Query();query1.addCriteria(Criteria.where("name").is("appleC"));User userTest3_1 = mongoOperation.findOne(query1, User.class);System.out.println("userTest3_1 - " + userTest3_1);
输出
userTest3 - User [id=id, ic=null, name=appleC, age=0, createdDate=null]
userTest3_1 - User [id=id, ic=1003, name=appleC, age=100, createdDate=Sat Apr 06 23:22:34 MYT 2013]
4.updateMulti 示例
更新与查询匹配的所有文档。
{ "_id" : ObjectId("id"), "ic" : "1004", "name" : "appleD", "age" : 20, "createdDate" : ISODate("2013-04-06T15:22:34.530Z")
}
{ "_id" : ObjectId("id"), "ic" : "1005", "name" : "appleE", "age" : 20, "createdDate" : ISODate("2013-04-06T15:22:34.530Z")
}
//show the use of $or operatorQuery query = new Query();query.addCriteria(Criteria.where("name").exists(true).orOperator(Criteria.where("name").is("appleD"),Criteria.where("name").is("appleE")));Update update = new Update();//update age to 11update.set("age", 11);//remove the createdDate fieldupdate.unset("createdDate");// if use updateFirst, it will update 1004 only.// mongoOperation.updateFirst(query4, update4, User.class);// update all matched, both 1004 and 1005mongoOperation.updateMulti(query, update, User.class);System.out.println(query.toString());List<User> usersTest4 = mongoOperation.find(query4, User.class);for (User userTest4 : usersTest4) {System.out.println("userTest4 - " + userTest4);}
输出
Query: { "name" : { "$exists" : true} , "$or" : [ { "name" : "appleD"} , { "name" : "appleE"}]}, Fields: null, Sort: nulluserTest4 - User [id=id, ic=1004, name=appleD, age=11, createdDate=null]
userTest4 - User [id=id, ic=1005, name=appleE, age=11, createdDate=null]
5.向上插入示例
如果文档匹配,则更新它,否则通过组合查询和更新对象创建一个新文档,其工作方式类似于findAndModifyElseCreate()
😃
{ //no data
}
//search a document that doesn't existQuery query = new Query();query.addCriteria(Criteria.where("name").is("appleZ"));Update update = new Update();update.set("age", 21);mongoOperation.upsert(query, update, User.class);User userTest5 = mongoOperation.findOne(query, User.class);System.out.println("userTest5 - " + userTest5);
输出,通过组合查询和更新对象创建一个新文档。
userTest5 - User [id=id, ic=null, name=appleZ, age=21, createdDate=null]
6.findAndModify 示例
从单个操作中查找、修改并获取新更新的对象。
{ "_id" : ObjectId("id"), "ic" : "1006", "name" : "appleF", "age" : 20, "createdDate" : ISODate("2013-04-07T13:11:34.530Z")
}
Query query6 = new Query();query6.addCriteria(Criteria.where("name").is("appleF"));Update update6 = new Update();update6.set("age", 101);update6.set("ic", 1111);//FindAndModifyOptions().returnNew(true) = newly updated document//FindAndModifyOptions().returnNew(false) = old document (not update yet)User userTest6 = mongoOperation.findAndModify(query6, update6, new FindAndModifyOptions().returnNew(true), User.class);System.out.println("userTest6 - " + userTest6);
输出
userTest6 - User [id=id, ic=1111, name=appleF, age=101, createdDate=Sun Apr 07 13:11:34 MYT 2013]
7.完整示例
完全适用于将例 1 到例 6 中的所有内容结合起来。
package com.mkyong.core;import java.util.ArrayList;
import java.util.Date;
import java.util.List;import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;import com.mkyong.config.SpringMongoConfig;
import com.mkyong.model.User;public class UpdateApp {public static void main(String[] args) {// For AnnotationApplicationContext ctx = new AnnotationConfigApplicationContext(SpringMongoConfig.class);MongoOperations mongoOperation = (MongoOperations) ctx.getBean("mongoTemplate");// insert 6 users for testingList<User> users = new ArrayList<User>();User user1 = new User("1001", "appleA", 20, new Date());User user2 = new User("1002", "appleB", 20, new Date());User user3 = new User("1003", "appleC", 20, new Date());User user4 = new User("1004", "appleD", 20, new Date());User user5 = new User("1005", "appleE", 20, new Date());User user6 = new User("1006", "appleF", 20, new Date());users.add(user1);users.add(user2);users.add(user3);users.add(user4);users.add(user5);users.add(user6);mongoOperation.insert(users, User.class);// Case 1 ... find and updateSystem.out.println("Case 1");Query query1 = new Query();query1.addCriteria(Criteria.where("name").is("appleA"));User userTest1 = mongoOperation.findOne(query1, User.class);System.out.println("userTest1 - " + userTest1);userTest1.setAge(99);mongoOperation.save(userTest1);User userTest1_1 = mongoOperation.findOne(query1, User.class);System.out.println("userTest1_1 - " + userTest1_1);// Case 2 ... select single field onlySystem.out.println("\nCase 2");Query query2 = new Query();query2.addCriteria(Criteria.where("name").is("appleB"));query2.fields().include("name");User userTest2 = mongoOperation.findOne(query2, User.class);System.out.println("userTest2 - " + userTest2);userTest2.setAge(99);mongoOperation.save(userTest2);// ooppss, you just override everything, it caused ic=null and// createdDate=nullQuery query2_1 = new Query();query2_1.addCriteria(Criteria.where("name").is("appleB"));User userTest2_1 = mongoOperation.findOne(query2_1, User.class);System.out.println("userTest2_1 - " + userTest2_1);System.out.println("\nCase 3");Query query3 = new Query();query3.addCriteria(Criteria.where("name").is("appleC"));query3.fields().include("name");User userTest3 = mongoOperation.findOne(query3, User.class);System.out.println("userTest3 - " + userTest3);Update update3 = new Update();update3.set("age", 100);mongoOperation.updateFirst(query3, update3, User.class);Query query3_1 = new Query();query3_1.addCriteria(Criteria.where("name").is("appleC"));User userTest3_1 = mongoOperation.findOne(query3_1, User.class);System.out.println("userTest3_1 - " + userTest3_1);System.out.println("\nCase 4");Query query4 = new Query();query4.addCriteria(Criteria.where("name").exists(true).orOperator(Criteria.where("name").is("appleD"),Criteria.where("name").is("appleE")));Update update4 = new Update();update4.set("age", 11);update4.unset("createdDate");// update 1004 only.// mongoOperation.updateFirst(query4, update4, User.class);// update all matchedmongoOperation.updateMulti(query4, update4, User.class);System.out.println(query4.toString());List<User> usersTest4 = mongoOperation.find(query4, User.class);for (User userTest4 : usersTest4) {System.out.println("userTest4 - " + userTest4);}System.out.println("\nCase 5");Query query5 = new Query();query5.addCriteria(Criteria.where("name").is("appleZ"));Update update5 = new Update();update5.set("age", 21);mongoOperation.upsert(query5, update5, User.class);User userTest5 = mongoOperation.findOne(query5, User.class);System.out.println("userTest5 - " + userTest5);System.out.println("\nCase 6");Query query6 = new Query();query6.addCriteria(Criteria.where("name").is("appleF"));Update update6 = new Update();update6.set("age", 101);update6.set("ic", 1111);User userTest6 = mongoOperation.findAndModify(query6, update6,new FindAndModifyOptions().returnNew(true), User.class);System.out.println("userTest6 - " + userTest6);mongoOperation.dropCollection(User.class);}}
输出
Case 1
userTest1 - User [id=id, ic=1001, name=appleA, age=20, createdDate=Sun Apr 07 13:22:48 MYT 2013]
userTest1_1 - User [id=id, ic=1001, name=appleA, age=99, createdDate=Sun Apr 07 13:22:48 MYT 2013]Case 2
userTest2 - User [id=id, ic=null, name=appleB, age=0, createdDate=null]
userTest2_1 - User [id=id, ic=null, name=appleB, age=99, createdDate=null]Case 3
userTest3 - User [id=id, ic=null, name=appleC, age=0, createdDate=null]
userTest3_1 - User [id=id, ic=1003, name=appleC, age=100, createdDate=Sun Apr 07 13:22:48 MYT 2013]Case 4
Query: { "name" : { "$exists" : true} , "$or" : [ { "name" : "appleD"} , { "name" : "appleE"}]}, Fields: null, Sort: null
userTest4 - User [id=id, ic=1004, name=appleD, age=11, createdDate=null]
userTest4 - User [id=id, ic=1005, name=appleE, age=11, createdDate=null]Case 5
userTest5 - User [id=id, ic=null, name=appleZ, age=21, createdDate=null]Case 6
userTest6 - User [id=id, ic=1006, name=appleF, age=20, createdDate=Sun Apr 07 13:22:48 MYT 2013]
下载源代码
Download it – SpringMongoDB-Update-Example.zip (29 KB)
参考
- MongoDB 模板更新文档
- Spring Data MongoDB–保存、更新和删除文档
- Java MongoDB 更新示例/
- MongoDB 更新修改器操作
- 春季数据 MongoDB Hello World 示例
mongodb spring-data update
spring——在 bean 配置文件中定义电子邮件模板
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-define-an-e-mail-template-in-bean-configuration-file/
在上一个 Spring 的电子邮件教程中,你在方法体中硬编码了所有的电子邮件属性和消息内容,这是不实际的,应该避免。您应该考虑在 Spring 的 bean 配置文件中定义电子邮件消息模板。
1.项目依赖性
添加 JavaMail 和 Spring 的依赖项。
文件: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>SpringExample</artifactId><packaging>jar</packaging><version>1.0-SNAPSHOT</version><name>SpringExample</name><url>http://maven.apache.org</url><repositories><repository><id>Java.Net</id><url>http://download.java.net/maven/2/</url></repository></repositories><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><!-- Java Mail API --><dependency><groupId>javax.mail</groupId><artifactId>mail</artifactId><version>1.4.3</version></dependency><!-- Spring framework --><dependency><groupId>org.springframework</groupId><artifactId>spring</artifactId><version>2.5.6</version></dependency></dependencies>
</project>
2.春天的邮件发送者
一个 Java 类,通过 Spring 的 MailSender 接口发送电子邮件,并使用 String.format 用 bean 配置文件中的传递变量替换电子邮件消息“ %s ”。
文件:MailMail.java
package com.mkyong.common;import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;public class MailMail
{private MailSender mailSender;private SimpleMailMessage simpleMailMessage;public void setSimpleMailMessage(SimpleMailMessage simpleMailMessage) {this.simpleMailMessage = simpleMailMessage;}public void setMailSender(MailSender mailSender) {this.mailSender = mailSender;}public void sendMail(String dear, String content) {SimpleMailMessage message = new SimpleMailMessage(simpleMailMessage);message.setText(String.format(simpleMailMessage.getText(), dear, content));mailSender.send(message);}
}
3.Bean 配置文件
在 bean 配置文件中定义电子邮件模板' customeMailMessage '和邮件发送者详细信息。
文件:Spring-Mail.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-2.5.xsd"><bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"><property name="host" value="smtp.gmail.com" /><property name="port" value="587" /><property name="username" value="username" /><property name="password" value="password" /><property name="javaMailProperties"><props><prop key="mail.smtp.auth">true</prop><prop key="mail.smtp.starttls.enable">true</prop></props></property>
</bean><bean id="mailMail" class="com.mkyong.common.MailMail"><property name="mailSender" ref="mailSender" /><property name="simpleMailMessage" ref="customeMailMessage" />
</bean><bean id="customeMailMessage"class="org.springframework.mail.SimpleMailMessage"><property name="from" value="from@no-spam.com" /><property name="to" value="to@no-spam.com" /><property name="subject" value="Testing Subject" /><property name="text"><value><![CDATA[Dear %s,Mail Content : %s]]></value></property>
</bean></beans>
4.运行它
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("Spring-Mail.xml");MailMail mm = (MailMail) context.getBean("mailMail");mm.sendMail("Yong Mook Kim", "This is text content");}
}
输出
Dear Yong Mook Kim,Mail Content : This is text content
下载源代码
Download it – Spring-Email-Gmail-Smtp-Template-Example.zipemail spring
在 Spring 中定义自定义@Required-style 注释
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-define-custom-required-style-annotation/
@Required 注释用于确保已经设置了特定的属性。如果您正在将现有项目迁移到 Spring framework,或者出于某种原因拥有自己的@Required-style 注释,Spring 允许您定义自定义的@Required-style 注释,这相当于@Required 注释。
在这个例子中,您将创建一个名为 @Mandatory 的自定义@Required-style
注释,它相当于@Required
注释。
1.创建@Mandatory 接口
package com.mkyong.common;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Mandatory {
}
2.将其应用于一个属性
package com.mkyong.common;public class Customer
{private Person person;private int type;private String action;@Mandatorypublic void setPerson(Person person) {this.person = person;}//getter and setter methods
}
3.注册它
在“RequiredAnnotationBeanPostProcessor”类中包含新的 @Mandatory 批注。
<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.RequiredAnnotationBeanPostProcessor"><property name="requiredAnnotationType" value="com.mkyong.common.Mandatory"/>
</bean><bean id="CustomerBean" class="com.mkyong.common.Customer"><property name="action" value="buy" /><property name="type" value="1" /></bean></beans>
4.完成的
完成后,您就创建了一个新的名为 @Mandatory 的自定义@Required-style 注释,它相当于@Required 注释。
spring
带有@Required 注释的 Spring 依赖检查
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-dependency-checking-with-required-annotation/
Spring 在 bean 配置文件中的依赖检查用于确保某个类型(原语、集合或对象)的所有属性都已设置。在大多数情况下,您只需要确保设置了特定的属性,而不是所有的属性..
对于这种情况,您需要 @Required 注释,参见以下示例:
@必需示例
一个客户对象,在 setPerson()方法中应用@Required 以确保已经设置了 Person 属性。
package com.mkyong.common;import org.springframework.beans.factory.annotation.Required;public class Customer
{private Person person;private int type;private String action;public Person getPerson() {return person;}@Requiredpublic void setPerson(Person person) {this.person = person;}
}
简单地应用@Required 注释将不会强制执行属性检查,您还需要注册一个RequiredAnnotationBeanPostProcessor来了解 bean 配置文件中的@Required 注释。
可以通过两种方式启用 RequiredAnnotationBeanPostProcessor。
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.包含 RequiredAnnotationBeanPostProcessor
在 bean 配置文件中直接包含“RequiredAnnotationBeanPostProcessor”。
<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.RequiredAnnotationBeanPostProcessor"/><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>
如果运行它,将会抛出下面的错误消息,因为 person 属性未设置。
org.springframework.beans.factory.BeanInitializationException: Property 'person' is required for bean 'CustomerBean'
结论
尝试@Required 批注,它比 XML 文件中的依赖检查更灵活,因为它只能应用于特定的属性。
Custom @Required
Please read this article about how to create a new custom @Required-style annotation.
参考
- http://static . springsource . org/spring/docs/2.5 . x/reference/metadata . html # metadata-annotations-required
弹簧依赖注入(DI)
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-dependency-injection-di/
在 Spring 框架中,依赖注入(DI)设计模式用于定义对象之间的依赖关系。它有两种主要类型:
- 定型剂注射
- 构造函数注入
1.定型剂注射
这是最流行和最简单的 DI 方法,它通过 setter 方法注入依赖。
例子
具有 setter 方法的 helper 类。
package com.mkyong.output;import com.mkyong.output.IOutputGenerator;public class OutputHelper
{IOutputGenerator outputGenerator;public void setOutputGenerator(IOutputGenerator outputGenerator){this.outputGenerator = outputGenerator;}}
一个 bean 配置文件,用于声明 bean 并通过 setter 注入(属性标签)设置依赖关系。
<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="OutputHelper" class="com.mkyong.output.OutputHelper"><property name="outputGenerator"><ref bean="CsvOutputGenerator" /></property></bean><bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator" />
<bean id="JsonOutputGenerator" class="com.mkyong.output.impl.JsonOutputGenerator" /></beans>
您只需通过 setter 方法(setOutputGenerator)将“CsvOutputGenerator”bean 注入到“OutputHelper”对象中。
2.构造函数注入
这个 DI 方法将通过构造函数注入依赖关系。
例子
带有构造函数的帮助器类。
package com.mkyong.output;import com.mkyong.output.IOutputGenerator;public class OutputHelper
{IOutputGenerator outputGenerator;OutputHelper(IOutputGenerator outputGenerator){this.outputGenerator = outputGenerator;}
}
一个 bean 配置文件,用于声明 bean 并通过构造函数注入(constructor-arg 标记)设置依赖关系。
<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="OutputHelper" class="com.mkyong.output.OutputHelper"><constructor-arg><bean class="com.mkyong.output.impl.CsvOutputGenerator" /></constructor-arg></bean><bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator" />
<bean id="JsonOutputGenerator" class="com.mkyong.output.impl.JsonOutputGenerator" /></beans>
您只需通过构造函数将“CsvOutputGenerator”bean 注入到“OutputHelper”对象中。
Setter 还是 Constructor 注入?
Spring framework 没有硬性规定,只需使用适合您项目需要的任何类型的 DI。然而,由于 setter 注入的简单性,它总是被大多数场景所选择。
参考
1.http://en.wikipedia.org/wiki/Dependency_injection
通过构造函数弹出 DI
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-di-via-constructor/
使用 Spring 通过构造函数依赖注入 bean。
1.IOutputGenerator
它的一个接口和实现类。
package com.mkyong.output;public interface IOutputGenerator
{public void generateOutput();
}
package com.mkyong.output.impl;import com.mkyong.output.IOutputGenerator;public class JsonOutputGenerator implements IOutputGenerator
{public void generateOutput(){System.out.println("This is Json Output Generator");}
}
2.助手类
一个助手类,稍后使用 Spring 通过构造函数来定义 IOutputGenerator。
package com.mkyong.output;import com.mkyong.output.IOutputGenerator;public class OutputHelper {IOutputGenerator outputGenerator;public void generateOutput() {outputGenerator.generateOutput();}//DI via constructorpublic OutputHelper(IOutputGenerator outputGenerator){this.outputGenerator = outputGenerator;}}
3.弹簧配置
请看下面的 Spring bean 配置,Spring 将 DI 上面的" JsonOutputGenerator "转换成这个" OutputHelper "类,通过构造函数"public output helper(ioutput generator output generator)"。
<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"><constructor-arg><ref bean="JsonOutputGenerator" /></constructor-arg></bean><bean id="JsonOutputGenerator" class="com.mkyong.output.impl.JsonOutputGenerator" /></beans>
4.运行它
加载所有内容,并运行它。
package com.mkyong.common;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mkyong.output.OutputHelper;public class App {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("SpringBeans.xml");OutputHelper output = (OutputHelper)context.getBean("OutputHelper");output.generateOutput();}
}
输出
This is Json Output Generator
Constructor type ambiguities
For constructor that supported multiple parameters, it will lead to common constructor injection type ambiguities issue, please read this solution.
下载源代码
Download it – Spring-DI-constructor-example.zip (6KB)dependency injection spring
通过 setter 方法的 Spring DI
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-di-via-setter-method/
一个简单的 Spring 示例,向您展示了如何通过 setter 方法(最常用的 DI 方法)依赖注入 bean。
1.IOutputGenerator
一个接口和它的实现类。
package com.mkyong.output;public interface IOutputGenerator
{public void generateOutput();
}
package com.mkyong.output.impl;import com.mkyong.output.IOutputGenerator;public class CsvOutputGenerator implements IOutputGenerator {public void generateOutput() {System.out.println("This is Csv Output Generator");}
}
2.助手类
一个助手类,稍后使用 Spring 来定义 IOutputGenerator。
package com.mkyong.output;import com.mkyong.output.IOutputGenerator;public class OutputHelper {IOutputGenerator outputGenerator;public void generateOutput() {outputGenerator.generateOutput();}//DI via setter methodpublic void setOutputGenerator(IOutputGenerator outputGenerator) {this.outputGenerator = outputGenerator;}
}
3.弹簧配置
在 Spring 配置文件中配置 bean,通过 property 标签,ref 属性,将 bean“CsvOutputGenerator”引用到“OutputHelper”中。
在这种情况下,Spring 会将 bean“CsvOutputGenerator”DI 为“OutputHelper”类,通过 setter 方法“setOutputGenerator(IOutputGenerator output generator)”。
<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="CsvOutputGenerator" /></bean><bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator" /></beans>
4.运行它
加载所有内容,并运行它。
package com.mkyong.common;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mkyong.output.OutputHelper;public class App {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("SpringBeans.xml");OutputHelper output = (OutputHelper)context.getBean("OutputHelper");output.generateOutput();}
}
输出
This is Csv Output Generator
下载源代码
Download it – Spring-DI-setter-method-example.zip (6KB)dependency injection spring
Spring EL bean 参考示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-el-bean-reference-example/
在 Spring EL 中,您可以引用一个 bean,并使用'点(.)符号。比如“ bean.property_name ”。
public class Customer {@Value("#{addressBean.country}")private String country;
在上面的代码片段中,它将" addressBean " bean "中的" country 属性的值注入到当前的" customer 类," country 属性中。
注释中的弹簧 EL
看下面的例子,向你展示如何使用 SpEL 来引用一个 bean,bean 属性和它的方法。
package com.mkyong.core;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component("customerBean")
public class Customer {@Value("#{addressBean}")private Address address;@Value("#{addressBean.country}")private String country;@Value("#{addressBean.getFullAddress('mkyong')}")private String fullAddress;//getter and setter methods@Overridepublic String toString() {return "Customer [address=" + address + "\n, country=" + country+ "\n, fullAddress=" + fullAddress + "]";}}
package com.mkyong.core;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component("addressBean")
public class Address {@Value("Block ABC, LakeView")private String street;@Value("98700")private int postcode;@Value("US")private String country;public String getFullAddress(String prefix) {return prefix + " : " + street + " " + postcode + " " + country;}//getter and setter methodspublic void setCountry(String country) {this.country = country;}@Overridepublic String toString() {return "Address [street=" + street + ", postcode=" + postcode+ ", country=" + country + "]";}}
运行它
Customer obj = (Customer) context.getBean("customerBean");System.out.println(obj);
输出
Customer [address=Address [street=Block ABC, LakeView, postcode=98700, country=US]
, country=US
, fullAddress=mkyong : Block ABC, LakeView 98700 US]
XML 中的 Spring EL
请参见 bean 定义 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-3.0.xsd"><bean id="customerBean" class="com.mkyong.core.Customer"><property name="address" value="#{addressBean}" /><property name="country" value="#{addressBean.country}" /><property name="fullAddress" value="#{addressBean.getFullAddress('mkyong')}" /></bean><bean id="addressBean" class="com.mkyong.core.Address"><property name="street" value="Block ABC, LakeView" /><property name="postcode" value="98700" /><property name="country" value="US" /></bean></beans>
下载源代码
Download It – Spring3-EL-Bean-Reference-Example.zip (6 KB)spring el spring3
Spring EL hello world 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-el-hello-world-example/
Spring EL 类似于 OGNL 和 JSF EL,在 bean 创建期间被评估或执行。此外,所有 Spring 表达式都可以通过 XML 或注释获得。
在本教程中,我们将向您展示如何使用Spring Expression Language(SpEL),在 XML 和注释中向属性中注入字符串、整数和 bean。
1.弹簧 EL 依赖关系
在 Maven pom.xml
文件中声明核心 Spring jars,它将自动下载 Spring EL 依赖项。
文件: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-context</artifactId><version>${spring.version}</version></dependency><dependencies>
2.春豆
两个简单的 beans,后来使用 SpEL 在 XML 和注释中将值注入到属性中。
package com.mkyong.core;public class Customer {private Item item;private String itemName;}
package com.mkyong.core;public class Item {private String name;private int qty;}
3.XML 中的 Spring EL
SpEL 用#{ SpEL expression }
括起来,参见 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-3.0.xsd"><bean id="itemBean" class="com.mkyong.core.Item"><property name="name" value="itemA" /><property name="qty" value="10" /></bean><bean id="customerBean" class="com.mkyong.core.Customer"><property name="item" value="#{itemBean}" /><property name="itemName" value="#{itemBean.name}" /></bean></beans>
- # { itemBean }–将“item bean”注入到“customer bean”bean 的“item”属性中。
- # { itemBean . name }–将“item bean”的“name”属性注入到“customer bean”bean 的“itemName”属性中。
4.注释中的弹簧 EL
请在注释模式下查看等效版本。
Note
To use SpEL in annotation, you must register your component via annotation. If you register your bean in XML and define @Value
in Java class, the @Value
will failed to execute.
package com.mkyong.core;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component("customerBean")
public class Customer {@Value("#{itemBean}")private Item item;@Value("#{itemBean.name}")private String itemName;//...}
package com.mkyong.core;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component("itemBean")
public class Item {@Value("itemA") //inject String directlyprivate String name;@Value("10") //inject interger directlyprivate int qty;public String getName() {return name;}//...
}
启用自动组件扫描。
<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-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><context:component-scan base-package="com.mkyong.core" /></beans>
在注释模式下,使用@Value
定义弹簧 EL。在这种情况下,您将一个字符串和整数值直接注入到" itemBean "中,然后将" itemBean "注入到" customerBean 属性中。
5.输出
运行它,XML 中的 SpEL 和注释都显示相同的结果:
package com.mkyong.core;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("SpringBeans.xml");Customer obj = (Customer) context.getBean("customerBean");System.out.println(obj);}
}
输出
Customer [item=Item [name=itemA, qty=10], itemName=itemA]
下载源代码
Download It – Spring3-EL-Hello-Worldr-Example.zip (6 KB)
参考
- 弹簧 EL 参考值
hello world spring el spring3
Spring EL 列表,地图示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-el-lists-maps-example/
在本文中,我们将向您展示如何使用 Spring EL 从映射和列表中获取值。实际上,SpEL 处理 Map 和 List 的方式和 Java 完全一样。参见示例:
//get map whete key = 'MapA'@Value("#{testBean.map['MapA']}")private String mapA;//get first value from list, list is 0-based.@Value("#{testBean.list[0]}")private String list;
注释中的弹簧 EL
这里,创建了一个HashMap
和ArrayList
,用一些初始数据进行测试。
package com.mkyong.core;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component("customerBean")
public class Customer {@Value("#{testBean.map['MapA']}")private String mapA;@Value("#{testBean.list[0]}")private String list;public String getMapA() {return mapA;}public void setMapA(String mapA) {this.mapA = mapA;}public String getList() {return list;}public void setList(String list) {this.list = list;}@Overridepublic String toString() {return "Customer [mapA=" + mapA + ", list=" + list + "]";}}
package com.mkyong.core;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Component;@Component("testBean")
public class Test {private Map<String, String> map;private List<String> list;public Test() {map = new HashMap<String, String>();map.put("MapA", "This is A");map.put("MapB", "This is B");map.put("MapC", "This is C");list = new ArrayList<String>();list.add("List0");list.add("List1");list.add("List2");}public Map<String, String> getMap() {return map;}public void setMap(Map<String, String> map) {this.map = map;}public List<String> getList() {return list;}public void setList(List<String> list) {this.list = list;}}
运行它
Customer obj = (Customer) context.getBean("customerBean");System.out.println(obj);
输出
Customer [mapA=This is A, list=List0]
XML 中的 Spring EL
请参见 bean 定义 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-3.0.xsd"><bean id="customerBean" class="com.mkyong.core.Customer"><property name="mapA" value="#{testBean.map['MapA']}" /><property name="list" value="#{testBean.list[0]}" /></bean><bean id="testBean" class="com.mkyong.core.Test" /></beans>
下载源代码
Download It – Spring3-EL-Map-List-Example.zip (6 KB)list map spring el spring3
Spring EL 方法调用示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-el-method-invocation-example/
Spring expression language (SpEL)允许开发人员使用表达式来执行方法,并将方法返回值注入到属性中,即所谓的“ SpEL 方法调用”。
注释中的弹簧 EL
查看如何使用 @Value 注释进行 Spring EL 方法调用。
package com.mkyong.core;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component("customerBean")
public class Customer {@Value("#{'mkyong'.toUpperCase()}")private String name;@Value("#{priceBean.getSpecialPrice()}")private double amount;public String getName() {return name;}public void setName(String name) {this.name = name;}public double getAmount() {return amount;}public void setAmount(double amount) {this.amount = amount;}@Overridepublic String toString() {return "Customer [name=" + name + ", amount=" + amount + "]";}}
package com.mkyong.core;import org.springframework.stereotype.Component;@Component("priceBean")
public class Price {public double getSpecialPrice() {return new Double(99.99);}}
输出
Customer [name=MKYONG, amount=99.99]
说明
在字符串文本上调用“toUpperCase()
”方法。
@Value("#{'mkyong'.toUpperCase()}")private String name;
对 bean ' priceBean '调用'getSpecialPrice()
方法。
@Value("#{priceBean.getSpecialPrice()}")private double amount;
XML 中的 Spring EL
这是 bean 定义 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-3.0.xsd"><bean id="customerBean" class="com.mkyong.core.Customer"><property name="name" value="#{'mkyong'.toUpperCase()}" /><property name="amount" value="#{priceBean.getSpecialPrice()}" /></bean><bean id="priceBean" class="com.mkyong.core.Price" /></beans>
输出
Customer [name=MKYONG, amount=99.99]
下载源代码
Download It – Spring3-EL-Method-Invocation-Example.zip (6 KB)spring el spring3
Spring EL 运算符示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-el-operators-example/
Spring EL 支持大多数标准的数学、逻辑或关系运算符。举个例子,
- 关系运算符–等于(==,eq),不等于(!=,ne),小于(【T2,lt),小于或等于(< =,le),大于(【T4,gt),大于或等于(> =,ge)。
- 逻辑运算符–and、or、and not(!).
- 数学运算符–加法(+)、减法(-)、乘法(*)、除法(/)、模数(%)和指数幂(^).
注释中的弹簧 EL
这个例子演示了 SpEL 中操作符的使用。
package com.mkyong.core;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component("customerBean")
public class Customer {//Relational operators@Value("#{1 == 1}") //trueprivate boolean testEqual;@Value("#{1 != 1}") //falseprivate boolean testNotEqual;@Value("#{1 < 1}") //falseprivate boolean testLessThan;@Value("#{1 <= 1}") //trueprivate boolean testLessThanOrEqual;@Value("#{1 > 1}") //falseprivate boolean testGreaterThan;@Value("#{1 >= 1}") //trueprivate boolean testGreaterThanOrEqual;//Logical operators , numberBean.no == 999@Value("#{numberBean.no == 999 and numberBean.no < 900}") //falseprivate boolean testAnd;@Value("#{numberBean.no == 999 or numberBean.no < 900}") //trueprivate boolean testOr;@Value("#{!(numberBean.no == 999)}") //falseprivate boolean testNot;//Mathematical operators@Value("#{1 + 1}") //2.0private double testAdd;@Value("#{'1' + '@' + '1'}") //1@1private String testAddString;@Value("#{1 - 1}") //0.0private double testSubtraction;@Value("#{1 * 1}") //1.0private double testMultiplication;@Value("#{10 / 2}") //5.0private double testDivision;@Value("#{10 % 10}") //0.0private double testModulus ;@Value("#{2 ^ 2}") //4.0private double testExponentialPower;@Overridepublic String toString() {return "Customer [testEqual=" + testEqual + ", testNotEqual="+ testNotEqual + ", testLessThan=" + testLessThan+ ", testLessThanOrEqual=" + testLessThanOrEqual+ ", testGreaterThan=" + testGreaterThan+ ", testGreaterThanOrEqual=" + testGreaterThanOrEqual+ ", testAnd=" + testAnd + ", testOr=" + testOr + ", testNot="+ testNot + ", testAdd=" + testAdd + ", testAddString="+ testAddString + ", testSubtraction=" + testSubtraction+ ", testMultiplication=" + testMultiplication+ ", testDivision=" + testDivision + ", testModulus="+ testModulus + ", testExponentialPower="+ testExponentialPower + "]";}}
package com.mkyong.core;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component("numberBean")
public class Number {@Value("999")private int no;public int getNo() {return no;}public void setNo(int no) {this.no = no;}}
运行它
Customer obj = (Customer) context.getBean("customerBean");System.out.println(obj);
输出
Customer [testEqual=true, testNotEqual=false, testLessThan=false, testLessThanOrEqual=true, testGreaterThan=false, testGreaterThanOrEqual=true, testAnd=false, testOr=true, testNot=false, testAdd=2.0, testAddString=1@1, testSubtraction=0.0, testMultiplication=1.0, testDivision=5.0, testModulus=0.0, testExponentialPower=4.0
]
XML 中的 Spring EL
请参见 bean 定义 XML 文件中的等效版本。在 XML 中,像“小于这样的符号总是不被支持的,相反,你应该使用上面所示的文本等价符号,例如(' < ' = ' lt ')和(' < = ' = ' le ')。
<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-3.0.xsd"><bean id="customerBean" class="com.mkyong.core.Customer"><property name="testEqual" value="#{1 == 1}" /><property name="testNotEqual" value="#{1 != 1}" /><property name="testLessThan" value="#{1 lt 1}" /><property name="testLessThanOrEqual" value="#{1 le 1}" /><property name="testGreaterThan" value="#{1 > 1}" /><property name="testGreaterThanOrEqual" value="#{1 >= 1}" /><property name="testAnd" value="#{numberBean.no == 999 and numberBean.no lt 900}" /><property name="testOr" value="#{numberBean.no == 999 or numberBean.no lt 900}" /><property name="testNot" value="#{!(numberBean.no == 999)}" /><property name="testAdd" value="#{1 + 1}" /><property name="testAddString" value="#{'1' + '@' + '1'}" /><property name="testSubtraction" value="#{1 - 1}" /><property name="testMultiplication" value="#{1 * 1}" /><property name="testDivision" value="#{10 / 2}" /><property name="testModulus" value="#{10 % 10}" /><property name="testExponentialPower" value="#{2 ^ 2}" /></bean><bean id="numberBean" class="com.mkyong.core.Number"><property name="no" value="999" /></bean></beans>
下载源代码
Download It - Spring3-EL-Operator-Example.zip (7 KB)
参考
- 官方春联运营商参考文献
spring el spring3
Spring EL 正则表达式示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-el-regular-expression-example/
Spring EL 支持正则表达式使用一个简单的关键字“ matches ”,真的很牛逼!举个例子,
@Value("#{'100' matches '\\d+' }")private boolean isDigit;
它通过正则表达式' \d+ '测试' 100 是否为有效数字。
注释中的弹簧 EL
请看下面的 Spring EL 正则表达式示例,其中一些混合了三元运算符,这使得 Spring EL 非常灵活和强大。
下面的例子应该是不言自明的。
package com.mkyong.core;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component("customerBean")
public class Customer {// email regular expressionString emailRegEx = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)" +"*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";// if this is a digit?@Value("#{'100' matches '\\d+' }")private boolean validDigit;// if this is a digit + ternary operator@Value("#{ ('100' matches '\\d+') == true ? " +"'yes this is digit' : 'No this is not a digit' }")private String msg;// if this emailBean.emailAddress contains a valid email address?@Value("#{emailBean.emailAddress matches customerBean.emailRegEx}")private boolean validEmail;//getter and setter methods, and constructor
}
package com.mkyong.core;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component("emailBean")
public class Email {@Value("nospam@abc.com")String emailAddress;//...
}
输出
Customer [isDigit=true, msg=yes this is digit, isValidEmail=true]
XML 中的 Spring EL
请参见 bean 定义 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-3.0.xsd"><bean id="customerBean" class="com.mkyong.core.Customer"><property name="validDigit" value="#{'100' matches '\d+' }" /><property name="msg"value="#{ ('100' matches '\d+') == true ? 'yes this is digit' : 'No this is not a digit' }" /><property name="validEmail"value="#{emailBean.emailAddress matches '^[_A-Za-z0-9-]+(\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})/ins> }" /></bean><bean id="emailBean" class="com.mkyong.core.Email"><property name="emailAddress" value="nospam@abc.com" /></bean></beans>
下载源代码
Download It – Spring3-EL-Regular-Expression-Example.zip (6 KB)
参考
- 电子邮件正则表达式示例
- Spring EL 三元运算符(if-then-else)示例
regex spring el spring3
Spring EL 三元运算符(if-then-else)示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-el-ternary-operator-if-then-else-example/
Spring EL 支持三元运算符,执行 if then else 条件检查。举个例子,
condition ? true : false
注释中的弹簧 EL
带@值标注的 Spring EL 三元运算符。在本例中,如果“ itemBean.qtyOnHand ”小于 100,则将“ customerBean.warning ”设置为 true,否则设置为 false。
package com.mkyong.core;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component("customerBean")
public class Customer {@Value("#{itemBean.qtyOnHand < 100 ? true : false}")private boolean warning;public boolean isWarning() {return warning;}public void setWarning(boolean warning) {this.warning = warning;}@Overridepublic String toString() {return "Customer [warning=" + warning + "]";}}
package com.mkyong.core;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component("itemBean")
public class Item {@Value("99")private int qtyOnHand;public int getQtyOnHand() {return qtyOnHand;}public void setQtyOnHand(int qtyOnHand) {this.qtyOnHand = qtyOnHand;}}
输出
Customer [warning=true]
XML 中的 Spring EL
请参见 bean 定义 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-3.0.xsd"><bean id="customerBean" class="com.mkyong.core.Customer"><property name="warning" value="#{itemBean.qtyOnHand < 100 ? true : false}" /></bean><bean id="itemBean" class="com.mkyong.core.Item"><property name="qtyOnHand" value="99" /></bean></beans>
输出
Customer [warning=true]
在 XML 中,需要将小于运算符“ < ”替换为“<;”。
下载源代码
Download It - Spring3-EL-Ternary-Operator-Example.zip (6 KB)spring el spring3
自动扫描中的弹簧过滤器组件
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-filtering-components-in-auto-scanning/
在本 Spring 自动组件扫描教程中,您将了解如何让 Spring 自动扫描您的组件。在这篇文章中,我们向您展示了如何在自动扫描过程中进行组件过滤。
1.过滤器组件–包括
参见下面的例子,使用 Spring " filtering 来扫描和注册与定义的" regex "匹配的组件名,即使该类没有用@Component 注释。
道层
package com.mkyong.customer.dao;public class CustomerDAO
{@Overridepublic String toString() {return "Hello , This is CustomerDAO";}
}
服务层
package com.mkyong.customer.services;import org.springframework.beans.factory.annotation.Autowired;
import com.mkyong.customer.dao.CustomerDAO;public class CustomerService
{@AutowiredCustomerDAO customerDAO;@Overridepublic String toString() {return "CustomerService [customerDAO=" + customerDAO + "]";}}
弹簧过滤。
<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" ><context:include-filter type="regex" expression="com.mkyong.customer.dao.*DAO.*" /><context:include-filter type="regex" expression="com.mkyong.customer.services.*Service.*" /></context:component-scan></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-AutoScan.xml"});CustomerService cust = (CustomerService)context.getBean("customerService");System.out.println(cust);}
}
输出
CustomerService [customerDAO=Hello , This is CustomerDAO]
在这个 XML 过滤中,所有文件的名称都包含 DAO 或 Service (DAO。、服务。) word 将被检测并注册到 Spring 容器中。
2.过滤器组件–排除
另一方面,你也可以排除指定的组件,以避免 Spring 检测并在 Spring 容器中注册它。
排除那些用@Service 注释的文件。
<context:component-scan base-package="com.mkyong.customer" ><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" /> </context:component-scan>
排除那些文件名中含有刀字的文件。
<context:component-scan base-package="com.mkyong" ><context:exclude-filter type="regex" expression="com.mkyong.customer.dao.*DAO.*" /> </context:component-scan>
下载源代码
Download It – Spring-Filter-Auto-Scan-Example.zipspring
spring——如何在 bean 中访问 message source(message source aware)
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-how-to-access-messagesource-in-bean-messagesourceaware/
在上一个教程中,您可以通过 ApplicationContext 获得消息源。但是对于获取 MessageSource 的 bean,您必须实现 MessageSourceAware 接口。
例子
一个 CustomerService 类,实现了 MessageSourceAware 接口,有一个 setter 方法来设置 MessageSource 属性。
During Spring container initialization, if any class which implements the MessageSourceAware interface, Spring will automatically inject the MessageSource into the class via setMessageSource(MessageSource messageSource) setter method.
package com.mkyong.customer.services;import java.util.Locale;import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;public class CustomerService implements MessageSourceAware
{private MessageSource messageSource;public void setMessageSource(MessageSource messageSource) {this.messageSource = messageSource;}public void printMessage(){String name = messageSource.getMessage("customer.name", new Object[] { 28, "http://www.mkyong.com" }, Locale.US);System.out.println("Customer name (English) : " + name);String namechinese = messageSource.getMessage("customer.name", new Object[] { 28, "http://www.mkyong.com" }, Locale.SIMPLIFIED_CHINESE);System.out.println("Customer name (Chinese) : " + namechinese);}}
运行它
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[] {"locale.xml","Spring-Customer.xml"});CustomerService cust = (CustomerService)context.getBean("customerService");cust.printMessage();}
}
All the properties files and XML files are reuse from the last ResourceBundleMessageSource tutorial.Download it – Spring-MessageSource-Example.zipspring (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/20190213133419/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
spring——如何在会话监听器中进行依赖注入
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-how-to-do-dependency-injection-in-your-session-listener/
Spring 附带了一个" ContextLoaderListener "监听器,用于将 Spring 依赖注入会话监听器。在本教程中,它通过在会话监听器中添加一个 Spring 依赖注入 bean 来修改这个 HttpSessionListener 示例。
1.春豆
创建一个简单的计数器服务来打印创建的会话总数。
文件:CounterService.java
package com.mkyong.common;public class CounterService{public void printCounter(int count){System.out.println("Total session created : " + count);}}
文件:counter . XML–Bean 配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<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="counterService" class="com.mkyong.common.CounterService" /></beans>
2.WebApplicationContextUtils
使用“WebApplicationContextUtils
”来获取 Spring 的上下文,然后您可以用正常的 Spring 方式获取任何声明的 Spring 的 bean。
文件:SessionCounterListener.java
package com.mkyong.common;import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;public class SessionCounterListener implements HttpSessionListener {private static int totalActiveSessions;public static int getTotalActiveSession(){return totalActiveSessions;}@Overridepublic void sessionCreated(HttpSessionEvent arg0) {totalActiveSessions++;System.out.println("sessionCreated - add one session into counter"); printCounter(arg0);}@Overridepublic void sessionDestroyed(HttpSessionEvent arg0) {totalActiveSessions--;System.out.println("sessionDestroyed - deduct one session from counter"); printCounter(arg0);} private void printCounter(HttpSessionEvent sessionEvent){HttpSession session = sessionEvent.getSession();ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(session.getServletContext());CounterService counterService = (CounterService) ctx.getBean("counterService");counterService.printCounter(totalActiveSessions);}
}
3.综合
唯一的问题是,您的 web 应用程序如何知道在哪里加载 Spring bean 配置文件?秘密就在“web.xml”文件中。
- 将“
ContextLoaderListener
”注册为第一个监听器,让您的 web 应用程序知道 Spring context loader。 - 配置“
contextConfigLocation
”并定义 Spring 的 bean 配置文件。
文件:web.xml
<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name>Archetype Created Web Application</display-name><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/Spring/counter.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><listener><listener-class>com.mkyong.common.SessionCounterListener</listener-class></listener><servlet><servlet-name>Spring DI Servlet Listener</servlet-name><servlet-class>com.mkyong.common.App</servlet-class></servlet><servlet-mapping><servlet-name>Spring DI Servlet Listener</servlet-name><url-pattern>/Demo</url-pattern></servlet-mapping></web-app>
文件:App.java
package com.mkyong.common;import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;public class App extends HttpServlet{public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException{HttpSession session = request.getSession(); //sessionCreated() is executedsession.setAttribute("url", "mkyong.com"); session.invalidate(); //sessionDestroyed() is executedPrintWriter out = response.getWriter();out.println("<html>");out.println("<body>");out.println("<h1>Spring Dependency Injection into Servlet Listenner</h1>");out.println("</body>");out.println("</html>"); }
}
启动 Tomcat,访问网址“http://localhost:8080/spring web example/Demo”。
输出
sessionCreated - add one session into counter
Total session created : 1
sessionDestroyed - deduct one session from counter
Total session created : 0
查看控制台输出,通过 Spring DI 获得计数器服务 bean,并打印会话总数。
结论
在 Spring 中,“ContextLoaderListener
”是将 Spring 依赖注入集成到几乎所有 web 应用程序的一种通用方式。
[计] 下载
Download It – SpringWeb-DI-Session-listener-Example.zipsession listener spring
Spring 将日期注入 bean 属性–custom Date editor
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-how-to-pass-a-date-into-bean-property-customdateeditor/
这个 Spring 示例向您展示了如何将一个“日期”注入到 bean 属性中。
package com.mkyong.common;import java.util.Date;public class Customer {Date date;public Date getDate() {return date;}public void setDate(Date date) {this.date = date;}@Overridepublic String toString() {return "Customer [date=" + date + "]";}}
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="customer" class="com.mkyong.common.Customer"><property name="date" value="2010-01-31" /></bean></beans>
运行它
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("SpringBeans.xml");Customer cust = (Customer) context.getBean("customer");System.out.println(cust);}
}
您将遇到以下错误消息:
Caused by: org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.lang.String] to required type [java.util.Date] for property 'date'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] torequired type [java.util.Date] for property 'date': no matching editors or conversion strategy found
解决办法
在 Spring 中,您可以通过两种方法注入日期:
1.工厂豆
声明一个日期格式 bean,在“客户”bean 中,引用“日期格式”bean 作为工厂 bean。工厂方法会调用SimpleDateFormat.parse()
自动将字符串转换成日期对象。
<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="dateFormat" class="java.text.SimpleDateFormat"><constructor-arg value="yyyy-MM-dd" /></bean><bean id="customer" class="com.mkyong.common.Customer"><property name="date"><bean factory-bean="dateFormat" factory-method="parse"><constructor-arg value="2010-01-31" /></bean></property></bean></beans>
2.自定义日期编辑器
声明一个 CustomDateEditor 类,将 String 转换成 java.util.Date 。
<bean id="dateEditor"class="org.springframework.beans.propertyeditors.CustomDateEditor"><constructor-arg><bean class="java.text.SimpleDateFormat"><constructor-arg value="yyyy-MM-dd" /></bean></constructor-arg><constructor-arg value="true" /></bean>
并声明另一个“CustomEditorConfigurer”,使 Spring 转换类型为 java.util.Date 的 bean 属性。
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"><property name="customEditors"><map><entry key="java.util.Date"><ref local="dateEditor" /></entry></map></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="dateEditor"class="org.springframework.beans.propertyeditors.CustomDateEditor"><constructor-arg><bean class="java.text.SimpleDateFormat"><constructor-arg value="yyyy-MM-dd" /></bean></constructor-arg><constructor-arg value="true" /></bean><bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"><property name="customEditors"><map><entry key="java.util.Date"><ref local="dateEditor" /></entry></map></property></bean><bean id="customer" class="com.mkyong.common.Customer"><property name="date" value="2010-02-31" /></bean></beans>
下载源代码
Download It – Spring-CustomDateEditor-Example.zip (5KB)
参考
- 春天房产编辑
date spring
Spring init 方法和 destroy 方法示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-init-method-and-destroy-method-example/
在 Spring 中,可以使用 init-method 和 destroy-method 作为 bean 配置文件中的属性,让 bean 在初始化和销毁时执行某些操作。替代初始化 Bean 和可处置 Bean 接口。
例子
这里有一个例子向你展示如何使用初始化方法和销毁方法。
package com.mkyong.customer.services;public class CustomerService
{String message;public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public void initIt() throws Exception {System.out.println("Init method after properties are set : " + message);}public void cleanUp() throws Exception {System.out.println("Spring Container is destroy! Customer clean up");}}
文件:Spring-Customer.xml ,定义 bean 中的 init-method 和 destroy-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="customerService" class="com.mkyong.customer.services.CustomerService" init-method="initIt" destroy-method="cleanUp"><property name="message" value="i'm property message" /></bean></beans>
运行它
package com.mkyong.common;import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.mkyong.customer.services.CustomerService;public class App
{public static void main( String[] args ){ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"Spring-Customer.xml"});CustomerService cust = (CustomerService)context.getBean("customerService");System.out.println(cust);context.close();}
}
configurableapplicationcontext . close 将关闭应用程序上下文,释放所有资源并销毁所有缓存的单体 beans。
输出
Init method after properties are set : i'm property message
com.mkyong.customer.services.CustomerService@47393f
...
INFO: Destroying singletons in org.springframework.beans.factory.
support.DefaultListableBeanFactory@77158a:
defining beans [customerService]; root of factory hierarchy
Spring Container is destroy! Customer clean up
设置 message 属性后调用 initIt() 方法,在 context.close()后调用 cleanUp() 方法;
Thoughts…
It’s always recommended to use init-method and destroy-method in bean configuration file, instead of implement the InitializingBean and DisposableBean interface to cause unnecessarily coupled your code to Spring. ## 下载源代码
Download It – Spring-init-method-destroy-method-Example.zipspring (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/20190310101557/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
Spring InitializingBean 和 DisposableBean 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-initializingbean-and-disposablebean-example/
在 Spring 中, InitializingBean 和 DisposableBean 是两个标记接口,这是 Spring 在 Bean 初始化和销毁时执行某些操作的有用方法。
- 对于 Bean 实现的 InitializingBean,它将在设置完所有 bean 属性后运行
afterPropertiesSet()
。 - 对于 Bean 实现的 DisposableBean,它将在 Spring 容器释放 bean 后运行
destroy()
。
例子
这里有一个例子向你展示如何使用 InitializingBean 和 DisposableBean 。实现 InitializingBean 和 DisposableBean 接口的 CustomerService bean,并具有消息属性。
package com.mkyong.customer.services;import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;public class CustomerService implements InitializingBean, DisposableBean
{String message;public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public void afterPropertiesSet() throws Exception {System.out.println("Init method after properties are set : " + message);}public void destroy() throws Exception {System.out.println("Spring Container is destroy! Customer clean up");}}
文件: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="message" value="i'm property message" /></bean></beans>
运行它
package com.mkyong.common;import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.mkyong.customer.services.CustomerService;public class App
{public static void main( String[] args ){ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"Spring-Customer.xml"});CustomerService cust = (CustomerService)context.getBean("customerService");System.out.println(cust);context.close();}
}
configurableapplicationcontext . close()将关闭应用程序上下文,释放所有资源并销毁所有缓存的单体 beans。它仅用于destroy()
方法演示:)
输出
Init method after properties are set : im property message
com.mkyong.customer.services.CustomerService@47393f
...
INFO: Destroying singletons in org.springframework.beans.factory.
support.DefaultListableBeanFactory@77158a:
defining beans [customerService]; root of factory hierarchy
Spring Container is destroy! Customer clean up
设置消息属性后,调用 afterPropertiesSet()方法。而 destroy()方法是在 context.close()之后调用的;
Thoughts…
I would not recommend to use InitializingBean and DisposableBean interface, because it will tight coupled your code to Spring. A better approach should be specifying the init-method and destroy-method attributes in your bean configuration file. ## 下载源代码
Download It – Spring-InitializingBean-DisposableBean-Example.zip ## 参考
- 初始化 Bean Javadoc
- 一次性 Bean Javadoc
spring
Spring 内部 bean 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-inner-bean-examples/
在 Spring framework 中,每当 bean 仅用于一个特定属性时,建议将其声明为内部 bean。并且 setter 注入'property
'和 constructor 注入'constructor-arg
'都支持内部 bean。
请看一个详细的例子来演示 Spring inner bean 的使用。
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;}@Overridepublic String toString() {return "Customer [person=" + person + "]";}
}
package com.mkyong.common;public class Person
{private String name;private String address;private int age;//getter and setter methods@Overridepublic String toString() {return "Person [address=" + address + ", age=" + age + ", name=" + name + "]";}
}
通常,您可以使用'ref
'属性将“Person”bean 引用到“Customer”bean 中,Person 属性如下:
<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="person" ref="PersonBean" /></bean><bean id="PersonBean" class="com.mkyong.common.Person"><property name="name" value="mkyong" /><property name="address" value="address1" /><property name="age" value="28" /></bean></beans>
一般来说,这样引用是没问题的,但是由于' mkyong' person bean 仅用于 Customer bean,因此最好将此' mkyong' person 声明为内部 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="CustomerBean" class="com.mkyong.common.Customer"><property name="person"><bean class="com.mkyong.common.Person"><property name="name" value="mkyong" /><property name="address" value="address1" /><property name="age" value="28" /></bean></property></bean>
</beans>
该内部 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="CustomerBean" class="com.mkyong.common.Customer"><constructor-arg><bean class="com.mkyong.common.Person"><property name="name" value="mkyong" /><property name="address" value="address1" /><property name="age" value="28" /></bean></constructor-arg></bean>
</beans>
Note
The id or name value in bean class is not necessary in an inner bean, it will simply ignored by the Spring container.
运行它
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[] {"Spring-Customer.xml"});Customer cust = (Customer)context.getBean("CustomerBean");System.out.println(cust);}
}
输出
Customer [person=Person [address=address1, age=28, name=mkyong]]
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/20190217092743/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
Spring JdbcTemplate batchUpdate()示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring/spring-jdbctemplate-batchupdate-example/
Spring JdbcTemplate
批量插入、批量更新以及@Transactional
示例。
使用的技术:
- Spring Boot 2.1.2 .版本
- 春季 JDBC 5.1.4 .发布
- maven3
- Java 8
1.批量插入
1.1 一起插入一批 SQL 插入。
BookRepository.java
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;public int[] batchInsert(List<Book> books) {return this.jdbcTemplate.batchUpdate("insert into books (name, price) values(?,?)",new BatchPreparedStatementSetter() {public void setValues(PreparedStatement ps, int i) throws SQLException {ps.setString(1, books.get(i).getName());ps.setBigDecimal(2, books.get(i).getPrice());}public int getBatchSize() {return books.size();}});}
1.2 如果批量太大,我们可以按较小的批量拆分。
BookRepository.java
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ParameterizedPreparedStatementSetter;public int[][] batchInsert(List<Book> books, int batchSize) {int[][] updateCounts = jdbcTemplate.batchUpdate("insert into books (name, price) values(?,?)",books,batchSize,new ParameterizedPreparedStatementSetter<Book>() {public void setValues(PreparedStatement ps, Book argument) throws SQLException {ps.setString(1, argument.getName());ps.setBigDecimal(2, argument.getPrice());}});return updateCounts;}
2.批量更新
2.1 与 SQL update 语句相同。
BookRepository.java
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;public int[] batchUpdate(List<Book> books) {return this.jdbcTemplate.batchUpdate("update books set price = ? where id = ?",new BatchPreparedStatementSetter() {public void setValues(PreparedStatement ps, int i) throws SQLException {ps.setBigDecimal(1, books.get(i).getPrice());ps.setLong(2, books.get(i).getId());}public int getBatchSize() {return books.size();}});}
2.2 按批次大小更新。
BookRepository.java
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ParameterizedPreparedStatementSetter;public int[][] batchUpdate(List<Book> books, int batchSize) {int[][] updateCounts = jdbcTemplate.batchUpdate("update books set price = ? where id = ?",books,batchSize,new ParameterizedPreparedStatementSetter<Book>() {public void setValues(PreparedStatement ps, Book argument) throws SQLException {ps.setBigDecimal(1, argument.getPrice());ps.setLong(2, argument.getId());}});return updateCounts;}
3.奔跑
3.1 创建一个表来测试批量插入和更新。
SpringBootApplication.java
startBookBatchUpdateApp(1000);void startBookBatchUpdateApp(int size) {jdbcTemplate.execute("CREATE TABLE books(" +"id SERIAL, name VARCHAR(255), price NUMERIC(15, 2))");List<Book> books = new ArrayList();for (int count = 0; count < size; count++) {books.add(new Book(NameGenerator.randomName(20), new BigDecimal(1.99)));}// batch insertbookRepository.batchInsert(books);List<Book> bookFromDatabase = bookRepository.findAll();// countlog.info("Total books: {}", bookFromDatabase.size());// randomlog.info("{}", bookRepository.findById(2L).orElseThrow(IllegalArgumentException::new));log.info("{}", bookRepository.findById(500L).orElseThrow(IllegalArgumentException::new));// update all books to 9.99bookFromDatabase.forEach(x -> x.setPrice(new BigDecimal(9.99)));// batch updatebookRepository.batchUpdate(bookFromDatabase);List<Book> updatedList = bookRepository.findAll();// countlog.info("Total books: {}", updatedList.size());// randomlog.info("{}", bookRepository.findById(2L).orElseThrow(IllegalArgumentException::new));log.info("{}", bookRepository.findById(500L).orElseThrow(IllegalArgumentException::new));}
输出
Total books: 1000
Book{id=2, name='FcRzgpauFtwfWibpzWog', price=1.99}
Book{id=500, name='htDvtGmksjfGmXGKOCaR', price=1.99}Total books: 1000
Book{id=2, name='FcRzgpauFtwfWibpzWog', price=9.99}
Book{id=500, name='htDvtGmksjfGmXGKOCaR', price=9.99}
4.@事务性
4.1 使用@Transactional
,任何故障都会导致整个操作回滚,不会添加任何书籍。
BookRepository.java
@Transactionalpublic int[][] batchInsert(List<Book> books, int batchSize) {int[][] updateCounts = jdbcTemplate.batchUpdate("insert into books (name, price) values(?,?)",books,batchSize,new ParameterizedPreparedStatementSetter<Book>() {public void setValues(PreparedStatement ps, Book argument) throws SQLException {ps.setString(1, argument.getName());ps.setBigDecimal(2, argument.getPrice());}});return updateCounts;}
4.2 尝试批量插入 1000 本书,其中#500 包含一个错误,并且整批将被回滚,没有书将被插入。
SpringBootApplication.java
startBookBatchUpdateRollBack(1000);void startBookBatchUpdateRollBack(int size) {jdbcTemplate.execute("CREATE TABLE books(" +"id SERIAL, name VARCHAR(255), price NUMERIC(15, 2))");List<Book> books = new ArrayList();for (int count = 0; count < size; count++) {if (count == 500) {// Create an invalid data for id 500, test rollback// Name max 255, this book has length of 300books.add(new Book(NameGenerator.randomName(300), new BigDecimal(1.99)));continue;}books.add(new Book(NameGenerator.randomName(20), new BigDecimal(1.99)));}try {// with @Transactional, any error, entire batch will be rolled backbookRepository.batchInsert(books, 100);} catch (Exception e) {System.err.println(e.getMessage());}List<Book> bookFromDatabase = bookRepository.findAll();// count = 0 , id 500 error, roll back alllog.info("Total books: {}", bookFromDatabase.size());}
输出
PreparedStatementCallback; SQL [insert into books (name, price) values(?,?)]; Value too long for column "NAME VARCHAR(255)" Total books: 0
下载源代码
$ git clone https://github.com/mkyong/spring-boot.git
$ cd spring-jdbc
参考
- JDBC 批处理操作 JavaDocs
- 春季 JDBC 文档
- Spring Boot JDBC 的例子 _
- Java JDBC 教程
Spring JdbcTemplate 处理大型结果集
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring/spring-jdbctemplate-handle-large-resultset/
Spring JdbcTemplate
示例获取一个大的ResultSet
并处理它。
PS 用 Java 8 和 Spring JDBC 5.1.4.RELEASE 测试过
1.获取大的结果集
下面的 1.1 是一个从表中获取所有数据的经典findAll
。
BookRepository.java
public List<Book> findAll() {return jdbcTemplate.query("select * from books",(rs, rowNum) ->new Book(rs.getLong("id"),rs.getString("name"),rs.getBigDecimal("price")));}
运行它,对于小数据,没问题。
List<Book> list = bookRepository.findAll();for (Book book : list) {//process it}
如果表包含超过百万的数据,findAll
方法中的RowMapper
将忙于转换对象并将所有对象放入一个List
,如果对象大小大于 Java 堆空间,请参见下面的错误:
java.lang.OutOfMemoryError: Java heap space
2.解决办法
我们可以增加堆的大小,但是更好的解决方案是使用RowCallbackHandler
逐行处理大的ResultSet
。
import org.springframework.jdbc.core.RowCallbackHandler;jdbcTemplate.query("select * from books", new RowCallbackHandler() {public void processRow(ResultSet resultSet) throws SQLException {while (resultSet.next()) {String name = resultSet.getString("Name");// process it}}});
下载源代码
$ git clone https://github.com/mkyong/spring-boot.git
$ cd spring-jdbc
参考
- RowCallbackHandler JavaDocs
- 使用 Java 8 流 API 和 Spring 的 JdbcTemplate
- 春季 JDBC 文档
- Spring Boot JDBC 的例子 _
- Java JDBC 教程
spring+JDBC template+JdbcDaoSupport 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-jdbctemplate-jdbcdaosupport-examples/
在 Spring JDBC 开发中,您可以使用JdbcTemplate
和JdbcDaoSupport
类来简化整个数据库操作过程。
在本教程中,我们将重用最后一个 Spring + JDBC 示例,以查看之前(不支持 JdbcTemplate)和之后(支持 JdbcTemplate)示例之间的不同。
1.没有 JdbcTemplate 的示例
如果没有 JdbcTemplate,您必须在所有 DAO 数据库操作方法(插入、更新和删除)中创建许多冗余代码(创建连接、关闭连接、处理异常)。它效率不高,难看,容易出错,而且单调乏味。
private DataSource dataSource;public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}public void insert(Customer customer){String sql = "INSERT INTO CUSTOMER " +"(CUST_ID, NAME, AGE) VALUES (?, ?, ?)";Connection conn = null;try {conn = dataSource.getConnection();PreparedStatement ps = conn.prepareStatement(sql);ps.setInt(1, customer.getCustId());ps.setString(2, customer.getName());ps.setInt(3, customer.getAge());ps.executeUpdate();ps.close();} catch (SQLException e) {throw new RuntimeException(e);} finally {if (conn != null) {try {conn.close();} catch (SQLException e) {}}}}
2.JdbcTemplate 示例
使用 JdbcTemplate,您可以节省大量的冗余代码,因为 JdbcTemplate 会自动处理它。
private DataSource dataSource;private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}public void insert(Customer customer){String sql = "INSERT INTO CUSTOMER " +"(CUST_ID, NAME, AGE) VALUES (?, ?, ?)";jdbcTemplate = new JdbcTemplate(dataSource);jdbcTemplate.update(sql, new Object[] { customer.getCustId(),customer.getName(),customer.getAge() });}
看到不同了吗?
3.JdbcDaoSupport 示例
通过扩展 JdbcDaoSupport,不再需要在您的类中设置 datasource 和 JdbcTemplate,您只需要将正确的 datasource 注入到 JdbcCustomerDAO 中。您可以通过使用 getJdbcTemplate()方法获得 JdbcTemplate。
public class JdbcCustomerDAO extends JdbcDaoSupport implements CustomerDAO{//no need to set datasource herepublic void insert(Customer customer){String sql = "INSERT INTO CUSTOMER " +"(CUST_ID, NAME, AGE) VALUES (?, ?, ?)";getJdbcTemplate().update(sql, new Object[] { customer.getCustId(),customer.getName(),customer.getAge() });}
<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="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/mkyongjava" /><property name="username" value="root" /><property name="password" value="password" /></bean></beans>
<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="customerDAO" class="com.mkyong.customer.dao.impl.JdbcCustomerDAO"><property name="dataSource" ref="dataSource" /></bean></beans>
Note
In Spring JDBC development, it’s always recommended to use JdbcTemplate
and JdbcDaoSupport
, instead of coding JDBC code yourself.
下载源代码
Download it – Spring-JDBC-Example.zip (15 KB)
Spring JdbcTemplate 查询示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring/spring-jdbctemplate-querying-examples/
这里有几个例子来展示如何使用 JdbcTemplate query()
方法从数据库中查询或提取数据。
1.查询单行
这里有两种方法可以从数据库中查询或提取单行记录,并将其转换为模型类。
1.1 自定义行映射器
一般来说,总是建议实现 RowMapper 接口来创建自定义的 RowMapper,以满足您的需求。
package com.mkyong.customer.model;import java.sql.ResultSet;
import java.sql.SQLException;import org.springframework.jdbc.core.RowMapper;public class CustomerRowMapper implements RowMapper
{public Object mapRow(ResultSet rs, int rowNum) throws SQLException {Customer customer = new Customer();customer.setCustId(rs.getInt("CUST_ID"));customer.setName(rs.getString("NAME"));customer.setAge(rs.getInt("AGE"));return customer;}}
将它传递给queryForObject()
方法,返回的结果将调用您的自定义mapRow()
方法来正确地将值匹配到。
public Customer findByCustomerId(int custId){String sql = "SELECT * FROM CUSTOMER WHERE CUST_ID = ?";Customer customer = (Customer)getJdbcTemplate().queryForObject(sql, new Object[] { custId }, new CustomerRowMapper());return customer;
}
1.2 BeanPropertyRowMapper
在 Spring 2.5 中,附带了一个方便的行映射器实现,称为“BeanPropertyRowMapper”,它可以通过匹配它们的名称将行的列值映射到属性。只需确保属性和列具有相同的名称,例如,属性“CUSTID”将与列名“custId”或下划线“CUST_ID”匹配。
public Customer findByCustomerId2(int custId){String sql = "SELECT * FROM CUSTOMER WHERE CUST_ID = ?";Customer customer = (Customer)getJdbcTemplate().queryForObject(sql, new Object[] { custId }, new BeanPropertyRowMapper(Customer.class));return customer;
}
2.查询多行
现在,从数据库中查询或提取多行,并将其转换为一个列表。
2.1 手动映射它
在多返回行中,queryForList()
方法不支持 RowMapper,需要手动映射。
public List<Customer> findAll(){String sql = "SELECT * FROM CUSTOMER";List<Customer> customers = new ArrayList<Customer>();List<Map> rows = getJdbcTemplate().queryForList(sql);for (Map row : rows) {Customer customer = new Customer();customer.setCustId((Long)(row.get("CUST_ID")));customer.setName((String)row.get("NAME"));customer.setAge((Integer)row.get("AGE"));customers.add(customer);}return customers;
}
2.2 BeanPropertyRowMapper
最简单的解决方案是使用 BeanPropertyRowMapper 类。
public List<Customer> findAll(){String sql = "SELECT * FROM CUSTOMER";List<Customer> customers = getJdbcTemplate().query(sql,new BeanPropertyRowMapper(Customer.class));return customers;
}
3.查询单个值
在此示例中,它显示了如何从数据库中查询或提取单个列值。
3.1 单列名称
它展示了如何以字符串形式查询单个列名。
public String findCustomerNameById(int custId){String sql = "SELECT NAME FROM CUSTOMER WHERE CUST_ID = ?";String name = (String)getJdbcTemplate().queryForObject(sql, new Object[] { custId }, String.class);return name;}
3.2 总行数
它展示了如何从数据库中查询总行数。
public int findTotalCustomer(){String sql = "SELECT COUNT(*) FROM CUSTOMER";int total = getJdbcTemplate().queryForInt(sql);return total;
}
运行它
package com.mkyong.common;import java.util.ArrayList;
import java.util.List;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mkyong.customer.dao.CustomerDAO;
import com.mkyong.customer.model.Customer;public class JdbcTemplateApp
{public static void main( String[] args ){ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Customer.xml");CustomerDAO customerDAO = (CustomerDAO) context.getBean("customerDAO");Customer customerA = customerDAO.findByCustomerId(1);System.out.println("Customer A : " + customerA);Customer customerB = customerDAO.findByCustomerId2(1);System.out.println("Customer B : " + customerB);List<Customer> customerAs = customerDAO.findAll();for(Customer cust: customerAs){System.out.println("Customer As : " + customerAs);}List<Customer> customerBs = customerDAO.findAll2();for(Customer cust: customerBs){System.out.println("Customer Bs : " + customerBs);}String customerName = customerDAO.findCustomerNameById(1);System.out.println("Customer Name : " + customerName);int total = customerDAO.findTotalCustomer();System.out.println("Total : " + total);}
}
结论
JdbcTemplate 类附带了许多有用的重载查询方法。建议在创建自己定制的查询方法之前参考现有的查询方法,因为 Spring 可能已经为您完成了。
下载源代码
Download it – Spring-JdbcTemplate-Querying-Example.zip (15 KB)jdbc spring
Spring + JDK 定时器调度器示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-jdk-timer-scheduler-example/
Note
Learn the JDK Timer scheduler example without Spring and compare the different with this example.
在这个例子中,您将使用 Spring 的 Scheduler API 来调度一个任务。
1.调度程序任务
创建调度程序任务…
package com.mkyong.common;public class RunMeTask
{public void printMe() {System.out.println("Run Me ~");}
}
<bean id="runMeTask" class="com.mkyong.common.RunMeTask" />
Spring 附带了一个MethodInvokingTimerTaskFactoryBean作为 JDK TimerTask 的替代。您可以在这里定义要调用的目标调度程序对象和方法。
<bean id="schedulerTask" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"><property name="targetObject" ref="runMeTask" /><property name="targetMethod" value="printMe" />
</bean>
Spring 附带了一个 ScheduledTimerTask 来代替 JDK 计时器。您可以在这里传递您的调度程序名称、延迟和周期。
<bean id="timerTask"class="org.springframework.scheduling.timer.ScheduledTimerTask"><property name="timerTask" ref="schedulerTask" /><property name="delay" value="1000" /><property name="period" value="60000" />
</bean>
2.定时器工厂 Bean
最后,您可以配置一个 TimerFactoryBean bean 来启动您的调度程序任务。
<bean class="org.springframework.scheduling.timer.TimerFactoryBean"><property name="scheduledTimerTasks"><list><ref local="timerTask" /></list></property>
</bean>
文件:Spring-Scheduler.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-2.5.xsd"><bean id="schedulerTask" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"><property name="targetObject" ref="runMeTask" /><property name="targetMethod" value="printMe" />
</bean><bean id="runMeTask" class="com.mkyong.common.RunMeTask" /><bean id="timerTask"class="org.springframework.scheduling.timer.ScheduledTimerTask"><property name="timerTask" ref="schedulerTask" /><property name="delay" value="1000" /><property name="period" value="60000" />
</bean><bean class="org.springframework.scheduling.timer.TimerFactoryBean"><property name="scheduledTimerTasks"><list><ref local="timerTask" /></list></property>
</bean></beans>
运行它
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("Spring-Scheduler.xml");}
}
没有代码需要调用调度程序任务, TimerFactoryBean 将在启动时运行您的调度任务。因此,Spring scheduler 将每 60 秒运行一次 printMe()方法,第一次执行时有 1 秒的延迟。
下载源代码
Download it – Spring-Scheduler-JDK-TimerExample.zipintegration scheduler spring timer
Spring ListFactoryBean 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-listfactorybean-example/
' ListFactoryBean '类为开发人员提供了在 Spring 的 Bean 配置文件中创建具体列表集合类(ArrayList 和 LinkedList)的方法。
这里有一个 ListFactoryBean 的例子,它会在运行时实例化一个 ArrayList,并将其注入到一个 Bean 属性中。
package com.mkyong.common;import java.util.List;public class Customer
{private List lists;//...
}
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 id="CustomerBean" class="com.mkyong.common.Customer"><property name="lists"><bean class="org.springframework.beans.factory.config.ListFactoryBean"><property name="targetListClass"><value>java.util.ArrayList</value></property><property name="sourceList"><list><value>1</value><value>2</value><value>3</value></list></property></bean></property></bean></beans>
或者,您也可以使用 util schema 和来实现同样的事情。
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-2.5.xsd"><bean id="CustomerBean" class="com.mkyong.common.Customer"><property name="lists"><util:list list-class="java.util.ArrayList"><value>1</value><value>2</value><value>3</value></util:list></property></bean></beans>
记得包括 util 模式,否则您将遇到以下错误
Caused by: org.xml.sax.SAXParseException: The prefix "util" for element "util:list" is not bound.
运行它…
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("SpringBeans.xml");Customer cust = (Customer) context.getBean("CustomerBean");System.out.println(cust);}
}
输出
Customer [lists=[1, 2, 3]] Type=[class java.util.ArrayList]
您已经实例化了 ArrayList,并在运行时将其注入到 Customer 的 lists 属性中。
下载源代码
Download It – Spring-ListFactoryBean-Example.zip (5KB) ## 参考
- ListFactoryBean Javadoc
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/20190302163354/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
弹簧松耦合示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-loosely-coupled-example/
面向对象的概念是一个很好的设计,可以把你的系统分成一组可重用的对象。然而,当系统变得越来越大时,尤其是在 Java 项目中,巨大的对象依赖总是紧密耦合的,导致对象很难管理或修改。在这种情况下,您可以使用 Spring framework 作为一个中心模块,轻松有效地管理所有的对象依赖关系。
输出生成器示例
我们来看一个例子,假设你的项目有一个功能,把内容输出到 Csv 或者 Json 格式。您的代码可能类似于以下示例:
文件:IOutputGenerator.java-输出生成器的接口
package com.mkyong.output;public interface IOutputGenerator
{public void generateOutput();
}
文件:CsvOutputGenerator.java——实现 IOutputGenerator 接口的 Csv 输出生成器。
package com.mkyong.output.impl;import com.mkyong.output.IOutputGenerator;public class CsvOutputGenerator implements IOutputGenerator
{public void generateOutput(){System.out.println("Csv Output Generator");}
}
文件:JsonOutputGenerator.java——实现 IOutputGenerator 接口的 Json 输出生成器。
package com.mkyong.output.impl;import com.mkyong.output.IOutputGenerator;public class JsonOutputGenerator implements IOutputGenerator
{public void generateOutput(){System.out.println("Json Output Generator");}
}
有几种方法可以调用 IOutputGenerator,以及如何使用 Spring 来避免对象之间的紧密耦合。
1.方法 1–直接调用它
正常方式,直接调用。
package com.mkyong.common;import com.mkyong.output.IOutputGenerator;
import com.mkyong.output.impl.CsvOutputGenerator;public class App
{public static void main( String[] args ){IOutputGenerator output = new CsvOutputGenerator();output.generateOutput();}
}
问题如果这段代码分散在你的项目中,那么输出生成器的每一个变化都会让你深受其害。
方法 2–用助手类调用它
您可能会考虑创建一个助手类,将所有输出实现都放入其中。
package com.mkyong.output;import com.mkyong.output.IOutputGenerator;
import com.mkyong.output.impl.CsvOutputGenerator;public class OutputHelper
{IOutputGenerator outputGenerator;public OutputHelper(){outputGenerator = new CsvOutputGenerator();}public void generateOutput(){outputGenerator.generateOutput();}}
通过助手类调用它。
package com.mkyong.common;import com.mkyong.output.OutputHelper;public class App
{public static void main( String[] args ){OutputHelper output = new OutputHelper();output.generateOutput(); }
}
问题
这看起来更优雅,你只需要管理一个助手类,然而助手类仍然与 CsvOutputGenerator 紧密耦合,输出生成器的每一个变化仍然涉及微小的代码变化。
方法 3–弹簧
在这种情况下,Spring 依赖注入(DI)是一个不错的选择。Spring 可以让你的输出生成器松耦合到输出生成器。
OutputHelper 类中的微小变化。
package com.mkyong.output;import com.mkyong.output.IOutputGenerator;public class OutputHelper
{IOutputGenerator outputGenerator;public void generateOutput(){outputGenerator.generateOutput();}public void setOutputGenerator(IOutputGenerator outputGenerator){this.outputGenerator = outputGenerator;}
}
创建一个 Spring bean 配置文件,并在这里声明所有的 Java 对象依赖项。
<!-- Spring-Common.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-2.5.xsd"><bean id="OutputHelper" class="com.mkyong.output.OutputHelper"><property name="outputGenerator" ref="CsvOutputGenerator" /></bean><bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator" /><bean id="JsonOutputGenerator" class="com.mkyong.output.impl.JsonOutputGenerator" /></beans>
称之为经由春天
package com.mkyong.common;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.mkyong.output.OutputHelper;public class App
{public static void main( String[] args ){ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"Spring-Common.xml"});OutputHelper output = (OutputHelper)context.getBean("OutputHelper");output.generateOutput();}
}
现在,您只需要为不同的输出生成器更改 Spring XML 文件。当输出改变时,您只需要修改 Spring XML 文件,不需要修改代码,这意味着更少的错误。
结论
使用 Spring framework——依赖注入(DI)对于对象依赖管理来说是一个有用的特性,它非常优雅、高度灵活并且便于维护,尤其是在大型 Java 项目中。
spring
Spring MapFactoryBean 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-mapfactorybean-example/
' MapFactoryBean '类为开发人员提供了在 Spring 的 Bean 配置文件中创建具体地图集合类(HashMap 和 TreeMap)的方法。
下面是一个 MapFactoryBean 的例子,它会在运行时实例化一个 HashMap,,并将其注入到一个 Bean 属性中。
package com.mkyong.common;import java.util.Map;public class Customer
{private Map maps;//...
}
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 id="CustomerBean" class="com.mkyong.common.Customer"><property name="maps"><bean class="org.springframework.beans.factory.config.MapFactoryBean"><property name="targetMapClass"><value>java.util.HashMap</value></property><property name="sourceMap"><map><entry key="Key1" value="1" /><entry key="Key2" value="2" /><entry key="Key3" value="3" /></map></property></bean></property></bean></beans>
或者,您也可以使用 util schema 和
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-2.5.xsd"><bean id="CustomerBean" class="com.mkyong.common.Customer"><property name="maps"><util:map map-class="java.util.HashMap"><entry key="Key1" value="1" /><entry key="Key2" value="2" /><entry key="Key3" value="3" /></util:map></property></bean></beans>
记得包括 util 模式,否则您将遇到以下错误
Caused by: org.xml.sax.SAXParseException: The prefix "util" for element "util:map" is not bound.
运行它…
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("SpringBeans.xml");Customer cust = (Customer)context.getBean("CustomerBean");System.out.println(cust);}
}
输出
Customer [maps={Key2=2, Key1=1, Key3=3}] Type=[class java.util.HashMap]
您已经实例化了一个 HashMap,并在运行时将其注入到 Customer 的 Map 属性中。
下载源代码
Download It – Spring-MapFactoryBean-Example.zip (5KB) ## 参考
- MapFactoryBean Javadoc
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/20190214233817/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
spring+mock ITO–无法模仿 save 方法?
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring-boot/spring-mockito-unable-to-mock-save-method/
尝试模仿一个存储库save()
方法,但是它总是返回 null?
用 Spring Boot 2 + Spring 数据 JPA 测试的 PS
@Testpublic void save_book_OK() throws Exception {Book newBook = new Book(1L, "Mockito Guide", "mkyong");when(mockRepository.save(newBook)).thenReturn(newBook);mockMvc.perform(post("/books").content("{json}").header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)).andExpect(status().isCreated());}
解决办法
1.Mockito 使用equals
进行参数匹配,尝试使用ArgumentMatchers.any
进行save
方法。
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;@Testpublic void save_book_OK() throws Exception {Book newBook = new Book(1L, "Mockito Guide", "mkyong");when(mockRepository.save(any(Book.class))).thenReturn(newBook);//...}
2.或者,为模型实现equals
和hashCode
。
package com.mkyong;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.math.BigDecimal;@Entity
public class Book {@Id@GeneratedValueprivate Long id;private String name;private String author;//...@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Book book = (Book) o;if (id != null ? !id.equals(book.id) : book.id != null) return false;if (name != null ? !name.equals(book.name) : book.name != null) return false;return author != null ? author.equals(book.author) : book.author == null;}@Overridepublic int hashCode() {int result = id != null ? id.hashCode() : 0;result = 31 * result + (name != null ? name.hashCode() : 0);result = 31 * result + (author != null ? author.hashCode() : 0);return result;}
}
参考
- Mockito docs
- 测试 Spring Boot 应用
Tags : mock mockito spring boot spring data jpa spring test unit test
相关文章
-
Spring Boot +朱尼特 5 +莫奇托
-
单元测试——什么是嘲讽?为什么呢?
-
Mockito - when()需要一个必须的参数
-
Spring Boot 测试无法自动连线 MockMvc
-
Mockito -如何模拟存储库 findById thenRetu
-
Spring Boot——如何初始化测试用的 Bean?
-
弹簧支架集成测试示例
-
Spring Boot 测试-如何禁用调试和信息 l
-
JSONAssert -如何对 JSON 数据进行单元测试
-
弹簧座+弹簧安全示例
spring MVC BeanNameUrlHandlerMapping 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-beannameurlhandlermapping-example/
在 Spring MVC 中,BeanNameUrlHandlerMapping是默认的处理程序映射机制,它将 URL 请求映射到 beans 的名称。举个例子,
<beans ...><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/><bean name="/welcome.htm" class="com.mkyong.common.controller.WelcomeController" /><bean name="/streetName.htm" class="com.mkyong.common.controller.StreetNameController" /><bean name="/process*.htm" class="com.mkyong.common.controller.ProcessController" /></beans>
在上面的例子中,如果 URI 模式
- /welcome.htm 被请求,DispatcherServlet 会将请求转发给“
WelcomeController
”。 - /streetName.htm 被请求,DispatcherServlet 将把请求转发给“
StreetNameController
”。 - /processCreditCard.htm 或 /process{any thing}。htm 被请求,DispatcherServlet 将把请求转发给“
ProcessController
”。
Note
Additionally, this mapping is support Ant style regex pattern match, see this AntPathMatcher javadoc for details.
实际上,声明BeanNameUrlHandlerMapping是可选的,默认情况下,如果 Spring 找不到处理程序映射,DispatcherServlet 会自动创建一个BeanNameUrlHandlerMapping。
因此,上面的 web.xml 文件等同于下面的 web.xml:
<beans ...><bean name="/welcome.htm" class="com.mkyong.common.controller.WelcomeController" /><bean name="/streetName.htm" class="com.mkyong.common.controller.StreetNameController" /><bean name="/process*.htm" class="com.mkyong.common.controller.ProcessController" /></beans>
下载源代码
Download it – SpringMVC-BeanNameUrlHandlerMapping-Example.zip (7 KB) ## 参考
- beannameurlhandermapping javadoc
- AntPathMatcher javadoc
spring mvc url mapping (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/20190218213232/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
Spring MVC 复选框和复选框示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-checkbox-and-checkboxes-example/
在 Spring MVC 中, <表单:checkbox / > 用于呈现一个 HTML 的复选框字段,复选框值在 JSP 页面内部是硬编码的;当 <表单:checkboxes / > 用于呈现多个复选框时,复选框值是在运行时生成的。
在本教程中,我们向您展示了 3 种呈现 HTML 复选框字段的不同方式:
1.–单个复选框
用一个布尔值生成一个经典的单个复选框。
public class Customer{boolean receiveNewsletter;//...
}
<form:checkbox path="receiveNewsletter" />
Checked by default…
If you set the “receiveNewsletter” boolean value to true, this checkbox will be checked. For example :
public class Customer{boolean receiveNewsletter = true;//...
}
2.–多个复选框
生成多个复选框并硬编码值。
public class Customer{String [] favLanguages;//...
}
<form:checkbox path="favLanguages" value="Java"/>Java
<form:checkbox path="favLanguages" value="C++"/>C++
<form:checkbox path="favLanguages" value=".Net"/>.Net
Checked by default…
If you want to make the checkbox with value “Java” is checked by default, you can initialize the “favLanguages” property with value “Java”. For example :
//SimpleFormController...@Overrideprotected Object formBackingObject(HttpServletRequest request)throws Exception {Customer cust = new Customer();cust.setFavLanguages(new String []{"Java"});return cust;}
3.–多个复选框
为复选框值生成一个运行时列表,并将其链接到 Spring 的表单标签 <表单:复选框> 。
//SimpleFormController...protected Map referenceData(HttpServletRequest request) throws Exception {Map referenceData = new HashMap();List<String> webFrameworkList = new ArrayList<String>();webFrameworkList.add("Spring MVC");webFrameworkList.add("Struts 1");webFrameworkList.add("Struts 2");webFrameworkList.add("Apache Wicket");referenceData.put("webFrameworkList", webFrameworkList);return referenceData;}
<form:checkboxes items="${webFrameworkList}" path="favFramework" />
Checked by default…
If you want to make 2 checkboxes with value “Spring MVC” and “Struts 2” are checked by default, you can initialize the “favFramework” property with value “Spring MVC” and “Struts 2”. Fro example :
//SimpleFormController...@Overrideprotected Object formBackingObject(HttpServletRequest request)throws Exception {Customer cust = new Customer();cust.setFavFramework(new String []{"Spring MVC","Struts 2"});return cust;}
Note
<form:checkboxes items="${dynamic-list}" path="property-to-store" />
对于多个复选框,只要“路径或“属性值等于任意一个“复选框值—$ { dynamic-list },匹配的复选框将被自动勾选。
完整复选框示例
让我们来看一个完整的 Spring MVC 复选框示例:
1.模型
存储复选框值的客户模型类。
文件:Customer.java
package com.mkyong.customer.model;public class Customer{//checkboxboolean receiveNewsletter = true; //checked itString [] favLanguages;String [] favFramework;public String[] getFavFramework() {return favFramework;}public void setFavFramework(String[] favFramework) {this.favFramework = favFramework;}public boolean isReceiveNewsletter() {return receiveNewsletter;}public void setReceiveNewsletter(boolean receiveNewsletter) {this.receiveNewsletter = receiveNewsletter;}public String[] getFavLanguages() {return favLanguages;}public void setFavLanguages(String[] favLanguages) {this.favLanguages = favLanguages;}
}
2.控制器
处理表单复选框值的 SimpleFormController。
文件:CheckBoxController.java
package com.mkyong.customer.controller;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import com.mkyong.customer.model.Customer;public class CheckBoxController extends SimpleFormController{public CheckBoxController(){setCommandClass(Customer.class);setCommandName("customerForm");}@Overrideprotected Object formBackingObject(HttpServletRequest request)throws Exception {Customer cust = new Customer();//Make "Spring MVC" and "Struts 2" as default checked valuecust.setFavFramework(new String []{"Spring MVC","Struts 2"});//Make "Java" as default checked valuecust.setFavLanguages(new String []{"Java"});return cust;}@Overrideprotected ModelAndView onSubmit(HttpServletRequest request,HttpServletResponse response, Object command, BindException errors)throws Exception {Customer customer = (Customer)command;return new ModelAndView("CustomerSuccess","customer",customer);}//Generate the data for web framework multiple checkboxesprotected Map referenceData(HttpServletRequest request) throws Exception {Map referenceData = new HashMap();List<String> webFrameworkList = new ArrayList<String>();webFrameworkList.add("Spring MVC");webFrameworkList.add("Struts 1");webFrameworkList.add("Struts 2");webFrameworkList.add("Apache Wicket");referenceData.put("webFrameworkList", webFrameworkList);return referenceData;}
}
3.验证器
一个简单的表单验证器确保“ favLanguages ”属性不为空。
文件:CheckBoxValidator.java
package com.mkyong.customer.validator;import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import com.mkyong.customer.model.Customer;public class CheckBoxValidator implements Validator{@Overridepublic boolean supports(Class clazz) {//just validate the Customer instancesreturn Customer.class.isAssignableFrom(clazz);}@Overridepublic void validate(Object target, Errors errors) {Customer cust = (Customer)target;if(cust.getFavLanguages().length==0){errors.rejectValue("favLanguages", "required.favLanguages");}}
}
文件:message.properties
required.favLanguages = Please select at least a favorite programming language!
4.视角
一个 JSP 页面展示了 Spring 的表单标签 <表单的使用:checkbox / > 和 <表单:checkboxes / > 。
文件:CustomerForm.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>Spring's form checkbox example</h2><form:form method="POST" commandName="customerForm"><form:errors path="*" cssClass="errorblock" element="div" /><table><tr><td>Subscribe to newsletter? :</td><td><form:checkbox path="receiveNewsletter" /></td><td><form:errors path="receiveNewsletter" cssClass="error" /></td></tr><tr><td>Favourite Languages :</td><td><form:checkbox path="favLanguages" value="Java" />Java <form:checkbox path="favLanguages" value="C++" />C++ <form:checkbox path="favLanguages" value=".Net" />.Net</td><td><form:errors path="favLanguages" cssClass="error" /></td></tr><tr><td>Favourite Web Frameworks :</td><td><form:checkboxes items="${webFrameworkList}"path="favFramework" /></td><td><form:errors path="favFramework" cssClass="error" /></td></tr><tr><td colspan="3"><input type="submit" /></td></tr></table></form:form></body>
</html>
使用 JSTL 循环显示已提交的复选框值。
文件:CustomerSuccess.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><html>
<body><h2>Spring's form checkbox example</h2>Receive Newsletter : ${customer.receiveNewsletter}<br />Favourite Languages :<c:forEach items="${customer.favLanguages}" var="current">[<c:out value="${current}" />]</c:forEach><br />Favourite Web Frameworks :<c:forEach items="${customer.favFramework}" var="current">[<c:out value="${current}" />]</c:forEach><br />
</body>
</html>
5.弹簧豆配置
全部链接起来~
<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"><beanclass="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.customer.controller.CheckBoxController"><property name="formView" value="CustomerForm" /><property name="successView" value="CustomerSuccess" /><!-- Map a validator --><property name="validator"><bean class="com.mkyong.customer.validator.CheckBoxValidator" /></property></bean><!-- Register the Customer.properties --><bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basename" value="message" /></bean><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></beans>
6.演示
访问页面-http://localhost:8080/SpringMVCForm/checkbox . htm
如果用户在提交表单时没有选择任何语言复选框值,则显示并突出显示错误消息。
如果表单提交成功,只需显示已提交的复选框值。
下载源代码
Download it – SpringMVCForm-CheckBox-Example.zip (10KB)
参考
- http://forum.springsource.org/showthread.php?t=80088&高亮显示=复选框
- http://forum.springsource.org/showthread.php?t=79133&高亮显示=复选框
- http://forum.springsource.org/showthread.php?t=46950&高亮=复选框
- http://tomasjurman . blogspot . com/2009/12/tag-checkboxes-in-spring-MVC . html
- http://www . mkyong . com/struts 2/how-to-set-default-value-for-multiple-checkboxes-in-struts-2/
checkbox spring mvc
spring MVC controllerclassnamehandler 映射示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-controllerclassnamehandlermapping-example/
在 Spring MVC 中,ControllerClassNameHandlerMapping使用约定将请求的 URL 映射到控制器(约定优先于配置)。它接受类名,删除“Controller”后缀(如果存在的话),并返回剩余的文本,小写并以“/”开头。
参见下面几个例子来演示这个ControllerClassNameHandlerMapping
类的用法。
1.之前和之后
默认情况下,Spring MVC 使用的是BeanNameUrlHandlerMapping
处理程序映射。
<beans ...><bean name="/welcome.htm" class="com.mkyong.common.controller.WelcomeController" /><bean name="/helloGuest.htm" class="com.mkyong.common.controller.HelloGuestController" /></beans>
为了启用ControllerClassNameHandlerMapping,在 bean 配置文件中声明了它,现在不再需要控制器的 bean 的名称。
<beans ...><bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.common.controller.WelcomeController" /><bean class="com.mkyong.common.controller.HelloGuestController" /></beans>
现在,Spring MVC 通过以下约定映射请求的 URL:
WelcomeController -> /welcome*
HelloGuestController -> /helloguest*
- /welcome . htm –> welcome controller。
- /welcome home . htm –> welcome controller。
- /hello guest . htm –> hello guest controller。
- /hello guest 12345 . htm –> hello guest controller。
- /helloGuest.htm,无法映射**/hello guest ***,“g”大小写不匹配。
2.区分大小写
为了解决上述区分大小写的问题,声明了“ caseSensitive ”属性并将其设置为 true。
<beans ...><bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" ><property name="caseSensitive" value="true" /></bean><bean class="com.mkyong.common.controller.WelcomeController" /><bean class="com.mkyong.common.controller.HelloGuestController" /></beans>
现在,Spring MVC 通过以下约定映射请求的 URL:
WelcomeController -> /welcome*
HelloGuestController -> /helloGuest*
- /hello guest . htm –> hello guest controller。
- /helloguest.htm,未能映射“/hello guest *”,“G”大小写不匹配。
3. pathPrefix
此外,您可以指定一个前缀来映射请求的 URL,声明一个“ pathPrefix 属性。
<beans ...><bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" ><property name="caseSensitive" value="true" /><property name="pathPrefix" value="/customer" /></bean><bean class="com.mkyong.common.controller.WelcomeController" /><bean class="com.mkyong.common.controller.HelloGuestController" /></beans>
现在,Spring MVC 通过以下约定映射请求的 URL:
WelcomeController -> /customer/welcome*
HelloGuestController -> /customer/helloGuest*
- /customer/welcome . htm –> welcome controller。
- /customer/hello guest . htm –> hello guest controller。
- /welcome.htm,失败。
- /helloGuest.htm,失败。
下载源代码
Download it – SpringMVC-ControllerClassNameHandlerMapping-Example.zip (7KB)
参考
- ControllerClassNameHandlerMapping javadoc
spring mvc
Spring MVC 异常处理示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-exception-handling-example/
在 J2EE / servlet web 应用程序中,您可以映射错误页面来指定如下异常:
web.xml
<error-page><error-code>404</error-code><location>/WEB-INF/pages/404.jsp</location></error-page><error-page><exception-type>com.mkyong.web.exception.CustomException</exception-type><location>/WEB-INF/pages/error/custom_error.jsp</location></error-page><error-page><exception-type>java.lang.Exception</exception-type><location>/WEB-INF/pages/generic_error.jsp</location></error-page>
上面的代码应该是自我探索的。如果异常处理功能存在于 servlet 容器中,为什么我们仍然需要使用 Spring 来处理异常?
一般来说,有两个原因:
- 自定义错误页面–servlet 容器会直接渲染错误页面;而 Spring 允许你将模型或数据填充到错误页面,这样你就可以定制一个更加用户友好的错误页面。
- 业务逻辑–Spring 允许您在呈现错误页面之前应用额外的业务逻辑,如日志、审计等。
在本教程中,我们将向您展示两个在 Spring 中处理异常的例子。
- 对于 Spring 2.x,我们在 XML 文件中使用
SimpleMappingExceptionResolver
。 - 对于 Spring 3.x,我们可以通过
@ExceptionHandler
注释来简化 XML 配置。
1.SimpleMappingExceptionResolver 示例
查看目录结构。
自定义异常。
CustomGenericException.java
package com.mkyong.web.exception;public class CustomGenericException extends RuntimeException {private static final long serialVersionUID = 1L;private String errCode;private String errMsg;//getter and setter methodspublic CustomGenericException(String errCode, String errMsg) {this.errCode = errCode;this.errMsg = errMsg;}}
这个控制器类,只是抛出一个CustomGenericException
,带有自定义的错误代码和错误描述。
CustomerController.java
package com.mkyong.web.controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import com.mkyong.web.exception.CustomGenericException;public class CustomerController extends AbstractController {@Overrideprotected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse response) throws Exception {throw new CustomGenericException("E888", "This is custom message - ABC");}}
查看下面的SimpleMappingExceptionResolver
:
mvc-dispatcher-servlet.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.0.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-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" /><beanclass="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/><!-- Register the bean --><bean class="com.mkyong.web.controller.CustomerController" /><beanclass="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"><property name="exceptionMappings"><props><prop key="com.mkyong.wb.exception.CustomGenericException">error/generic_error</prop><prop key="java.lang.Exception">error/exception_error</prop></props></property></bean><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix"><value>/WEB-INF/pages/</value></property><property name="suffix"><value>.jsp</value></property></bean><mvc:annotation-driven /></beans>
在上面,当
- 抛出 CustomGenericException,它将映射到视图名“error/generic_error”。
- 任何其他异常被抛出,它将映射到视图名“error/exception_error”。
在 JSP 页面中,可以通过${exception}
访问异常实例。
pages/error/generic_error.jsp.jsp
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body><c:if test="${not empty exception.errCode}"><h1>${exception.errCode} : System Errors</h1></c:if><c:if test="${empty exception.errCode}"><h1>System Errors</h1></c:if><c:if test="${not empty exception.errMsg}"><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script><script>(adsbygoogle = window.adsbygoogle || []).push({});
</script><h2>${exception.errMsg}</h2></c:if></body>
</html>
演示-http://localhost:8080/spring MVC example/customer
Download it – SpringMvc-SimpleMappingExceptionResolver-Example.zip (13KB) ## 2.@ExceptionHandler 示例
从 Spring 3.0 开始,有了一个新的注释@ExceptionHandler
来简化 XML 配置。下面是使用@ExceptionHandler
的等效版本。
CustomerController.java
package com.mkyong.web.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.mkyong.web.exception.CustomGenericException;@Controller
public class CustomerController {@RequestMapping(value = "/customer", method = RequestMethod.GET)public ModelAndView getPages() throws Exception {throw new CustomGenericException("E888", "This is custom message X");}@ExceptionHandler(CustomGenericException.class)public ModelAndView handleCustomException(CustomGenericException ex) {ModelAndView model = new ModelAndView("error/generic_error");model.addObject("exception", ex);return model;}@ExceptionHandler(Exception.class)public ModelAndView handleAllException(Exception ex) {ModelAndView model = new ModelAndView("error/exception_error");return model;}}
Spring XML 文件中没有要声明的内容。
mvc-dispatcher-servlet.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.0.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-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" /><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix"><value>/WEB-INF/pages/</value></property><property name="suffix"><value>.jsp</value></property></bean><mvc:annotation-driven /></beans>
Download it – SpringMvc-ExceptionHandler-Example.zip (15KB)Note
You may interest at this Spring MVC @ExceptionHandler Example
参考
- SimpleMappingExceptionResolver JavaDoc
- @ExceptionHandler JavaDoc
- Spring MVC @ExceptionHandler 示例
exception handler spring mvc (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/20190225100332/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
通过 AbstractExcelView 弹出 MVC 和 Excel 文件
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-export-data-to-excel-file-via-abstractexcelview/
Spring MVC 自带 AbstractExcelView 类,通过 Apache POI 库将数据导出到 Excel 文件。在本教程中,将展示如何在 Spring MVC 应用程序中使用 AbstractExcelView 类将数据导出到 Excel 文件以供下载。
1.Apache 然后
获取 Apache POI 库来创建 excel 文件。
<!-- Excel library --> <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.6</version></dependency>
2.控制器
一个控制器类,生成虚拟数据用于演示,并获取请求参数以确定返回哪个视图。如果请求参数等于“Excel”,则返回一个 EXCEL 视图( AbstractExcelView )。
文件:RevenueReportController.java
package com.mkyong.common.controller;import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;public class RevenueReportController extends AbstractController{@Overrideprotected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse response) throws Exception {String output =ServletRequestUtils.getStringParameter(request, "output");//dummy dataMap<String,String> revenueData = new HashMap<String,String>();revenueData.put("Jan-2010", "$100,000,000");revenueData.put("Feb-2010", "$110,000,000");revenueData.put("Mar-2010", "$130,000,000");revenueData.put("Apr-2010", "$140,000,000");revenueData.put("May-2010", "$200,000,000");if(output ==null || "".equals(output)){//return normal viewreturn new ModelAndView("RevenueSummary","revenueData",revenueData);}else if("EXCEL".equals(output.toUpperCase())){//return excel viewreturn new ModelAndView("ExcelRevenueSummary","revenueData",revenueData);}else{//return normal viewreturn new ModelAndView("RevenueSummary","revenueData",revenueData);} }
}
3.AbstractExcelView
通过扩展 AbstractExcelView 类创建一个 Excel 视图,并覆盖 buildExcelDocument() 方法将数据填充到 Excel 文件中。 AbstractExcelView 正在使用 Apache POI API 创建 Excel 文件细节。
Note
For detail about how to use the Apache POI , please refer to Apache POI documentation
文件:ExcelRevenueReportView.java
package com.mkyong.common.view;import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.web.servlet.view.document.AbstractExcelView;public class ExcelRevenueReportView extends AbstractExcelView{@Overrideprotected void buildExcelDocument(Map model, HSSFWorkbook workbook,HttpServletRequest request, HttpServletResponse response)throws Exception {Map<String,String> revenueData = (Map<String,String>) model.get("revenueData");//create a wordsheetHSSFSheet sheet = workbook.createSheet("Revenue Report");HSSFRow header = sheet.createRow(0);header.createCell(0).setCellValue("Month");header.createCell(1).setCellValue("Revenue");int rowNum = 1;for (Map.Entry<String, String> entry : revenueData.entrySet()) {//create the row dataHSSFRow row = sheet.createRow(rowNum++);row.createCell(0).setCellValue(entry.getKey());row.createCell(1).setCellValue(entry.getValue());}}
}
Note
Alternatively, you can use the AbstractJExcelView, which is using the JExcelAPI to create the same Excel view, see this AbstractJExcelView example.
4.弹簧配置
为 Excel 视图创建一个 XmlViewResolver 。
<beans ...><beanclass="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.common.controller.RevenueReportController" /><bean class="org.springframework.web.servlet.view.XmlViewResolver"><property name="location"><value>/WEB-INF/spring-excel-views.xml</value></property></bean></beans>
文件:spring-excel-views.xml
<bean id="ExcelRevenueSummary"class="com.mkyong.common.view.ExcelRevenueReportView"></bean>
5.演示
URL:http://localhost:8080/springmvc/revenue report . htm?output=excel
它生成一个 Excel 文件供用户下载。
下载源代码
Download it – SpringMVC-ExcelFile-AbstractExcelView-Example.zip (9KB)
参考
- 阿帕奇兴趣点
- AbstractExcelView Javadoc
- Spring MVC 通过 AbstractJExcelView 将数据导出到 Excel 文件
- Spring MVC XmlViewResolver 示例
excel spring mvc
通过 AbstractJExcelView 弹出 MVC 和 Excel 文件
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-export-data-to-excel-file-via-abstractjexcelview/
Spring MVC 自带 AbstractJExcelView 类,通过 JExcelAPI 库将数据导出到 Excel 文件。在本教程中,将展示如何在 Spring MVC 应用程序中使用 AbstractJExcelView 类将数据导出到 Excel 文件以供下载。
1.杰克斯拉皮
获取 JExcelAPI 库。
<!-- JExcelAPI library --> <dependency><groupId>net.sourceforge.jexcelapi</groupId><artifactId>jxl</artifactId><version>2.6.3</version></dependency>
2.控制器
一个控制器类,生成虚拟数据用于演示,并获取请求参数以确定返回哪个视图。如果请求参数等于“Excel”,则返回一个 EXCEL 视图( AbstractJExcelView )。
文件:RevenueReportController.java
package com.mkyong.common.controller;import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;public class RevenueReportController extends AbstractController{@Overrideprotected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse response) throws Exception {String output =ServletRequestUtils.getStringParameter(request, "output");//dummy dataMap<String,String> revenueData = new HashMap<String,String>();revenueData.put("Jan-2010", "$100,000,000");revenueData.put("Feb-2010", "$110,000,000");revenueData.put("Mar-2010", "$130,000,000");revenueData.put("Apr-2010", "$140,000,000");revenueData.put("May-2010", "$200,000,000");if(output ==null || "".equals(output)){//return normal viewreturn new ModelAndView("RevenueSummary","revenueData",revenueData);}else if("EXCEL".equals(output.toUpperCase())){//return excel viewreturn new ModelAndView("ExcelRevenueSummary","revenueData",revenueData);}else{//return normal viewreturn new ModelAndView("RevenueSummary","revenueData",revenueData);} }
}
3.抽象视图
通过扩展 AbstractJExcelView 类创建一个 Excel 视图,并覆盖 buildExcelDocument() 方法将数据填充到 Excel 文件中。 AbstractJExcelView 正在使用
Note
For detail about how to use the JExcelAPI , please refer to the JExcelAPI documentation
文件:ExcelRevenueReportView.java
package com.mkyong.common.view;import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jxl.write.Label;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import org.springframework.web.servlet.view.document.AbstractJExcelView;public class ExcelRevenueReportView extends AbstractJExcelView{@Overrideprotected void buildExcelDocument(Map model, WritableWorkbook workbook,HttpServletRequest request, HttpServletResponse response)throws Exception {Map<String,String> revenueData = (Map<String,String>) model.get("revenueData");WritableSheet sheet = workbook.createSheet("Revenue Report", 0);sheet.addCell(new Label(0, 0, "Month"));sheet.addCell(new Label(1, 0, "Revenue"));int rowNum = 1;for (Map.Entry<String, String> entry : revenueData.entrySet()) {//create the row datasheet.addCell(new Label(0, rowNum, entry.getKey()));sheet.addCell(new Label(1, rowNum, entry.getValue()));rowNum++;}}
}
Note
Alternatively, you can use the AbstractExcelView, which is using the Apache POI API to create the same Excel view, see this AbstractExcelView example.
4.弹簧配置
为 Excel 视图创建一个 XmlViewResolver 。
<beans ...><bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.common.controller.RevenueReportController" /><bean class="org.springframework.web.servlet.view.XmlViewResolver"><property name="location"><value>/WEB-INF/spring-excel-views.xml</value></property></bean></beans>
文件:spring-excel-views.xml
<beans ..."><bean id="ExcelRevenueSummary"class="com.mkyong.common.view.ExcelRevenueReportView"></bean></beans>
5.演示
URL:http://localhost:8080/springmvc/revenue report . htm?output=excel
它生成一个 Excel 文件供用户下载。
下载源代码
Download it – SpringMVC-ExcelFile-AbstractJExcelView-Example.zip (9KB)
参考
- JExcelAPI 文件
- AbstractJExcelView Javadoc
- Spring MVC 通过 AbstractExcelView 将数据导出到 Excel 文件
Tags : excel spring mvc
相关文章
-
通过 AbstractExcelView 弹出 MVC 和 Excel 文件
-
如何在 Java 中获取 HTTP 请求头
-
jQuery - Ajax 请求返回 200 OK 但错误偶
-
Ant - Spring MVC 和 WAR 文件示例
-
Maven -如何创建一个 Java web 应用项目
-
混合 XML 和 JavaConfig
-
春季 MVC 教程
-
无法更改 HTTP 接受标头-使用不同的
-
春天 3 休息你好世界示例
-
Spring 3 MVC ContentNegotiatingViewResolver 示例
通过 AbstractPdfView 的 Spring MVC 和 PDF 文件
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-export-data-to-pdf-file-via-abstractpdfview/
Spring MVC 自带 AbstractPdfView 类,通过 Bruno Lowagie 的 iText 库将数据导出为 pdf 文件。在本教程中,展示了在 Spring MVC 应用程序中使用 AbstractPdfView 类将数据导出为 pdf 文件以供下载。
1. iText
获取 iText 库生成 pdf 文件。
<!-- Pdf library --> <dependency><groupId>com.lowagie</groupId><artifactId>itext</artifactId><version>2.1.7</version></dependency>
2.控制器
一个控制器类,生成虚拟数据用于演示,并获取请求参数以确定返回哪个视图。如果请求参数等于“ PDF ”,则返回一个 PDF 视图( AbstractPdfView )。
文件:RevenueReportController.java
package com.mkyong.common.controller;import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;public class RevenueReportController extends AbstractController{@Overrideprotected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse response) throws Exception {String output =ServletRequestUtils.getStringParameter(request, "output");//dummy dataMap<String,String> revenueData = new HashMap<String,String>();revenueData.put("1/20/2010", "$100,000");revenueData.put("1/21/2010", "$200,000");revenueData.put("1/22/2010", "$300,000");revenueData.put("1/23/2010", "$400,000");revenueData.put("1/24/2010", "$500,000");if(output ==null || "".equals(output)){//return normal viewreturn new ModelAndView("RevenueSummary","revenueData",revenueData);}else if("PDF".equals(output.toUpperCase())){//return excel viewreturn new ModelAndView("PdfRevenueSummary","revenueData",revenueData);}else{//return normal viewreturn new ModelAndView("RevenueSummary","revenueData",revenueData);} }
}
3.PdfRevenueReportView
通过扩展 AbstractPdfView 类创建 pdf 视图,覆盖 buildExcelDocument() 方法将数据填充到 pdf 文件中。 AbstractPdfView 正在使用
档案:PdfRevenueReportView.java
package com.mkyong.common.view;import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.view.document.AbstractPdfView;
import com.lowagie.text.Document;
import com.lowagie.text.Table;
import com.lowagie.text.pdf.PdfWriter;public class PdfRevenueReportView extends AbstractPdfView{@Overrideprotected void buildPdfDocument(Map model, Document document,PdfWriter writer, HttpServletRequest request,HttpServletResponse response) throws Exception {Map<String,String> revenueData = (Map<String,String>) model.get("revenueData");Table table = new Table(2);table.addCell("Month");table.addCell("Revenue");for (Map.Entry<String, String> entry : revenueData.entrySet()) {table.addCell(entry.getKey());table.addCell(entry.getValue());}document.add(table);}
}
4.弹簧配置
为 Pdf 视图创建一个 XmlViewResolver 。
<beans ...><bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.common.controller.RevenueReportController" /><bean class="org.springframework.web.servlet.view.XmlViewResolver"><property name="location"><value>/WEB-INF/spring-pdf-views.xml</value></property></bean></beans>
文件:spring-pdf-views.xml
<beans ..."><bean id="PdfRevenueSummary"class="com.mkyong.common.view.PdfRevenueReportView"></bean></beans>
5.演示
URL:http://localhost:8080/springmvc/revenue report . htm?output=pdf
它生成一个 pdf 文件供用户下载。
下载源代码
Download it – SpringMVC-PDF-Example.zip (9KB)
参考
- iText 网站
- iText Wiki
- AbstractPdfView Javadoc
Tags : pdf spring mvc
相关文章
-
如何用 Java 打开 PDF 文件
-
如何在 Java 中获取 HTTP 请求头
-
jQuery - Ajax 请求返回 200 OK 但错误偶
-
Ant - Spring MVC 和 WAR 文件示例
-
Maven -如何创建一个 Java web 应用项目
-
混合 XML 和 JavaConfig
-
春季 MVC 教程
-
无法更改 HTTP 接受标头-使用不同的
-
春天 3 休息你好世界示例
-
Spring 3 MVC ContentNegotiatingViewResolver 示例
Spring MVC 无法转换文件上载表单中的属性值
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-failed-to-convert-property-value-in-file-upload-form/
问题
在 Spring MVC 应用中,在点击文件上传按钮的同时,命中以下属性类型转换错误?
无法将[org . spring framework . web . multipart . commons . commonsmultipartfile]类型的属性值转换为属性文件所需的类型[byte[]];嵌套异常为 Java . lang . illegalargumentexception:无法将[org . spring framework . web . multipart . commons . commonsmultipartfile]类型的值转换为属性文件[0]所需的类型[byte]:property editor[org . spring framework . beans . property editors . customnumbereditor]返回了不适当的值
下面是 SimpleFormController …
public class FileUploadController extends SimpleFormController{public FileUploadController(){setCommandClass(FileUpload.class);setCommandName("fileUploadForm");}//...public class FileUpload{byte[] file;//...
}
解决办法
这是在 Spring MVC 中处理上传文件的常见问题,它无法自动将上传文件转换为字节数组。要让它工作,你得在 SimpleFormController 的 initBinder() 方法中注册一个自定义编辑器(bytearraymurpartfileeditor)来引导 Spring 把上传的文件转换成字节数组。
public class FileUploadController extends SimpleFormController{public FileUploadController(){setCommandClass(FileUpload.class);setCommandName("fileUploadForm");}@Overrideprotected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder)throws ServletException {// Convert multipart object to byte[]binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor());}//...
file upload spring mvc (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/20190220130945/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
Spring MVC 文件上传示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-file-upload-example/
Spring 使用MultipartResolver
接口来处理 web 应用中的文件上传,有两种实现方式:
StandardServletMultipartResolver
–Servlet 3.0 多部分请求解析。CommonsMultipartResolver
–Classic commons-file upload . jar
本文中使用的工具:
- 弹簧 4.3.5 .释放
- maven3
- Tomcat 7 或 8、Jetty 9 或任何 Servlet 3.0 容器
简而言之,本文向您展示了如何在 Spring MVC web 应用程序中处理文件上传,以及如何处理常见的超出最大文件大小异常。
Note
This article will focus on the Servlet 3.0 multipart request parsing.
P.S 文章从 Spring 2.5.x 更新到 Spring 4.3.x
1.项目结构
一个标准的 Maven 项目结构。
## 2.项目依赖性
标准的 Spring 依赖,不需要额外的文件上传库。
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-file-upload</artifactId><packaging>war</packaging><version>1.0-SNAPSHOT</version><name>Spring MVC file upload</name><properties><jdk.version>1.8</jdk.version><spring.version>4.3.5.RELEASE</spring.version><jstl.version>1.2</jstl.version><servletapi.version>3.1.0</servletapi.version><logback.version>1.1.3</logback.version><jcl.slf4j.version>1.7.12</jcl.slf4j.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><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><!-- 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></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>/spring4upload</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>/spring4upload</wtpContextName></configuration></plugin></plugins></build></project>
3.MultipartConfigElement
创建一个 Servlet 初始化器类并注册一个javax.servlet.MultipartConfigElement
MyWebInitializer.java
package com.mkyong;import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletRegistration;
import java.io.File;public class MyWebInitializer extendsAbstractAnnotationConfigDispatcherServletInitializer {private int maxUploadSizeInMb = 5 * 1024 * 1024; // 5 MB@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[]{SpringWebMvcConfig.class};}@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}@Overrideprotected Class<?>[] getRootConfigClasses() {return null;}@Overrideprotected void customizeRegistration(ServletRegistration.Dynamic registration) {// upload temp file will put hereFile uploadDirectory = new File(System.getProperty("java.io.tmpdir"));// register a MultipartConfigElementMultipartConfigElement multipartConfigElement =new MultipartConfigElement(uploadDirectory.getAbsolutePath(),maxUploadSizeInMb, maxUploadSizeInMb * 2, maxUploadSizeInMb / 2);registration.setMultipartConfig(multipartConfigElement);}}
查看 MultipartConfigElement 方法签名。
public MultipartConfigElement(java.lang.String location,long maxFileSize,long maxRequestSize,int fileSizeThreshold)
4.弹簧配置
注册一个multipartResolver
bean,并返回StandardServletMultipartResolver
SpringWebMvcConfig.java
package com.mkyong;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;@EnableWebMvc
@Configuration
@ComponentScan({"com.mkyong"})
public class SpringWebMvcConfig extends WebMvcConfigurerAdapter {// Bean name must be "multipartResolver", by default Spring uses method name as bean name.@Beanpublic MultipartResolver multipartResolver() {return new StandardServletMultipartResolver();}/*// if the method name is different, you must define the bean name manually like this :@Bean(name = "multipartResolver")public MultipartResolver createMultipartResolver() {return new StandardServletMultipartResolver();}*/@Beanpublic InternalResourceViewResolver viewResolver() {InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();viewResolver.setViewClass(JstlView.class);viewResolver.setPrefix("/WEB-INF/views/jsp/");viewResolver.setSuffix(".jsp");return viewResolver;}}
在这个阶段,Servlet 3.0 多部分请求解析配置正确,您可以开始上传文件了。
4.单个文件上传
4.1 普通 HTML 表单标签。
upload.jsp
<html><body>
<h1>Spring MVC file upload example</h1><form method="POST" action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data"><input type="file" name="file" /><br/><input type="submit" value="Submit" />
</form></body>
</html>
4.2 显示上传状态的另一个页面。
uploadStatus.jsp
<html>
<body>
<h1>Upload Status</h1>
<h2>Message : ${message}</h2>
</body>
</html>
4.3 在控制器中,将上传的文件映射到MultipartFile
UploadController.java
package com.mkyong.controller;import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
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;
import java.util.StringJoiner;@Controller
public class UploadController {//Save the uploaded file to this folderprivate static String UPLOADED_FOLDER = "F://temp//";@GetMapping("/")public String index() {return "upload";}//@RequestMapping(value = "/upload", method = RequestMethod.POST)@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";}}
5.多文件上传
5.1 只需添加更多的文件输入。
uploadMulti.jsp
<html><body>
<h1>Spring MVC multi files upload example</h1><form method="POST" action="${pageContext.request.contextPath}/uploadMulti" enctype="multipart/form-data"><input type="file" name="files" /><br/><input type="file" name="files" /><br/><input type="file" name="files" /><br/><input type="submit" value="Submit" />
</form></body>
</html>
5.2 在 Spring Controller 中,将多个上传的文件映射到MultipartFile []
UploadController.java
//...@PostMapping("/uploadMulti")public String multiFileUpload(@RequestParam("files") MultipartFile[] files,RedirectAttributes redirectAttributes) {StringJoiner sj = new StringJoiner(" , ");for (MultipartFile file : files) {if (file.isEmpty()) {continue; //next pls}try {byte[] bytes = file.getBytes();Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());Files.write(path, bytes);sj.add(file.getOriginalFilename());} catch (IOException e) {e.printStackTrace();}}String uploadedFileName = sj.toString();if (StringUtils.isEmpty(uploadedFileName)) {redirectAttributes.addFlashAttribute("message", "Please select a file to upload");} else {redirectAttributes.addFlashAttribute("message", "You successfully uploaded '" + uploadedFileName + "'");}return "redirect:/uploadStatus";}@GetMapping("/uploadMultiPage")public String uploadMultiPage() {return "uploadMulti";}//...
6.超过句柄最大上传大小
为了处理常见的超过最大上传大小的异常,声明一个@ControllerAdvice
并捕获MultipartException
GlobalExceptionHandler.java
package com.mkyong.exception;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 {@ExceptionHandler(MultipartException.class)public String handleError1(MultipartException e, RedirectAttributes redirectAttributes) {redirectAttributes.addFlashAttribute("message", e.getCause().getMessage());return "redirect:/uploadStatus";}// For commons-fileupload solution/*@ExceptionHandler(MaxUploadSizeExceededException.class)public String handleError2(MaxUploadSizeExceededException e, RedirectAttributes redirectAttributes) {redirectAttributes.addFlashAttribute("message", e.getCause().getMessage());return "redirect:/uploadStatus";}*/
}
Tomcat Connection Reset
If you deployed to Tomcat, and unable to catch the file size exceeded exception, this may cause by the Tomcat maxSwallowSize
setting. Read this – Spring file upload and connection reset issue
7.演示
获取下面的源代码,并使用嵌入式 Jetty 服务器mvn jetty:run
进行测试。
7.1 回顾上面的pom.xml
,嵌入式 Jetty 将在这个/spring4upload
上下文中部署 web 应用程序。
Terminal
project $ mvn jetty:run
//...
[INFO] Started o.e.j.m.p.JettyWebAppContext@341672e{/spring4upload,file:/SpringMVCUploadExample/src/main/webapp/,AVAILABLE}{file:/SpringMVCUploadExample/src/main/webapp/}
[WARNING] !RequestLog
[INFO] Started ServerConnector@3ba1308d{HTTP/1.1}{0.0.0.0:8080}
[INFO] Started @3743ms
[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 10 seconds.
7.2 访问http://localhost:8080/spring 4 upload
7.3 选择一个文件'myfirstexel . XML'并上传。
7.4 访问http://localhost:8080/spring 4 upload/upload multipage
7.5 选择几个文件并上传。
7.6 选择一个大于 5mb 的文件,您将访问此页面。
8.下载源代码
Download – spring-mvc-file-upload-example.zip (10 KB)
P.S 对于 Spring 2.5.x,试试这个Spring . 2.5-file-upload-example . zip(10KB)
参考
- 春季上传文件
- Spring 的多部分(文件上传)支持
file upload multipart spring mvc
Spring MVC 表单错误标签示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-form-errors-tag-example/
在 Spring MVC 中,字段错误消息由与控制器相关联的验证器生成,您可以使用 < form:errors / > 标签在默认的 HTML“span”标签中呈现这些字段错误消息。举个例子,
1.验证器
验证器检查“用户名字段,如果为空,从资源包向控制器返回“必需.用户名错误消息。
//...
public class TextBoxValidator implements Validator{@Overridepublic void validate(Object target, Errors errors) {ValidationUtils.rejectIfEmptyOrWhitespace(errors, "username", "required.username");}
}
/*** required.username = username is required! ***/
2.显示字段错误
然后,您可以使用 <表单:errors / > 来呈现与“用户名字段相关联的错误消息。
<form:errors path="userName" cssClass="error" />
它将使用一个默认的“ span ”元素来呈现和封装错误消息,该元素包含一个 CSS 类“ error ”。
<span id="username.errors" class="error">username is required!</span>
Note
- path = " * "–显示与任何字段相关的所有错误消息。
- path = " username "–仅显示与“username”字段相关的错误消息。
3.自定义输出元素
出于某些原因,比如 CSS 格式化的目的,您可能需要用不同的元素来包含错误消息,而不是默认的“ span 标签。为此,只需在“元素属性中指定 prefer 元素:
<form:errors path="userName" cssClass="error" element="div" />
现在,它用一个“ div ”元素呈现并封装错误消息,该元素包含一个“错误”的 CSS 类。
<div id="username.errors" class="error">username is required!</div>
4.演示
下载源代码
Download it – SpringMVCForm-TextBox-Example.zip (9KB)form handling spring mvc
Spring MVC 表单处理注释示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-form-handling-annotation-example/
在本教程中,我们将向您展示如何在 Spring MVC web 应用程序中使用注释进行表单处理。
Note
This annotation-based example is converted from the last Spring MVC form handling XML-based example. So, please compare and spots the different.
1.简单表单控制器与@控制器
在基于 XML 的 Spring MVC web 应用程序中,您通过扩展SimpleFormController
类来创建表单控制器。
在基于注释的情况下,可以使用@控制器来代替。
简单表单控制器
public class CustomerController extends SimpleFormController{//...
}
标注
@Controller
@RequestMapping("/customer.htm")
public class CustomerController{//...
}
2.formBackingObject()vs request method。得到
在 SimpleFormController 中,可以在 formBackingObject() 方法中初始化命令对象进行绑定。在基于注释的方法中,您可以通过用@ request mapping(method = request method)注释方法名来做同样的事情。搞定)。
简单表单控制器
@Overrideprotected Object formBackingObject(HttpServletRequest request)throws Exception {Customer cust = new Customer();//Make "Spring MVC" as default checked valuecust.setFavFramework(new String []{"Spring MVC"});return cust;}
标注
@RequestMapping(method = RequestMethod.GET)public String initForm(ModelMap model){Customer cust = new Customer();//Make "Spring MVC" as default checked valuecust.setFavFramework(new String []{"Spring MVC"});//command objectmodel.addAttribute("customer", cust);//return form viewreturn "CustomerForm";}
3. onSubmit()诉 RequestMethod.POST
在 SimpleFormController 中,表单提交由 onSubmit() 方法处理。在基于注释的方法中,您可以通过用@ request mapping(method = request method)注释方法名来做同样的事情。后)。
简单表单控制器
@Overrideprotected ModelAndView onSubmit(HttpServletRequest request,HttpServletResponse response, Object command, BindException errors)throws Exception {Customer customer = (Customer)command;return new ModelAndView("CustomerSuccess");}
标注
@RequestMapping(method = RequestMethod.POST)public String processSubmit(@ModelAttribute("customer") Customer customer,BindingResult result, SessionStatus status) {//clear the command object from the sessionstatus.setComplete(); //return form success viewreturn "CustomerSuccess";}
4.reference data()vs @ model attribute
在 SimpleFormController 中,通常通过 referenceData() 方法将引用数据放入模型中,以便表单视图可以访问它。在基于注释的方法中,您可以通过用 @ModelAttribute 注释方法名来做同样的事情。
简单表单控制器
@Overrideprotected Map referenceData(HttpServletRequest request) throws Exception {Map referenceData = new HashMap();//Data referencing for web framework checkboxesList<String> webFrameworkList = new ArrayList<String>();webFrameworkList.add("Spring MVC");webFrameworkList.add("Struts 1");webFrameworkList.add("Struts 2");webFrameworkList.add("JSF");webFrameworkList.add("Apache Wicket");referenceData.put("webFrameworkList", webFrameworkList);return referenceData;}
弹簧的形状
<form:checkboxes items="${webFrameworkList}" path="favFramework" />
标注
@ModelAttribute("webFrameworkList")public List<String> populateWebFrameworkList() {//Data referencing for web framework checkboxesList<String> webFrameworkList = new ArrayList<String>();webFrameworkList.add("Spring MVC");webFrameworkList.add("Struts 1");webFrameworkList.add("Struts 2");webFrameworkList.add("JSF");webFrameworkList.add("Apache Wicket");return webFrameworkList;}
弹簧的形状
<form:checkboxes items="${webFrameworkList}" path="favFramework" />
5.initBinder()与@InitBinder
在 SimpleFormController 中,通过 initBinder() 方法定义绑定或注册自定义属性编辑器。在基于注释的方法中,您可以通过用 @InitBinder 注释方法名来做同样的事情。
简单表单控制器
protected void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception {SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));}
标注
@InitBinderpublic void initBinder(WebDataBinder binder) {SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));}
来自验证
在 SimpleFormController 中,您必须通过 XML bean 配置文件注册验证器类并将其映射到控制器类,验证检查和工作流将自动执行。
在基于注释的情况下,您必须显式执行验证器,并手动在 @Controller 类中定义验证流。看到不同的:
简单表单控制器
<bean class="com.mkyong.customer.controller.CustomerController"><property name="formView" value="CustomerForm" /><property name="successView" value="CustomerSuccess" /><!-- Map a validator --><property name="validator"><bean class="com.mkyong.customer.validator.CustomerValidator" /></property></bean>
标注
@Controller
@RequestMapping("/customer.htm")
public class CustomerController{CustomerValidator customerValidator;@Autowiredpublic CustomerController(CustomerValidator customerValidator){this.customerValidator = customerValidator;}@RequestMapping(method = RequestMethod.POST)public String processSubmit(@ModelAttribute("customer") Customer customer,BindingResult result, SessionStatus status) {customerValidator.validate(customer, result);if (result.hasErrors()) {//if validator failedreturn "CustomerForm";} else {status.setComplete();//form successreturn "CustomerSuccess";}}//...
完整示例
查看完整的@Controller 示例。
package com.mkyong.customer.controller;import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.support.SessionStatus;import com.mkyong.customer.model.Customer;
import com.mkyong.customer.validator.CustomerValidator;@Controller
@RequestMapping("/customer.htm")
public class CustomerController{CustomerValidator customerValidator;@Autowiredpublic CustomerController(CustomerValidator customerValidator){this.customerValidator = customerValidator;}@RequestMapping(method = RequestMethod.POST)public String processSubmit(@ModelAttribute("customer") Customer customer,BindingResult result, SessionStatus status) {customerValidator.validate(customer, result);if (result.hasErrors()) {//if validator failedreturn "CustomerForm";} else {status.setComplete();//form successreturn "CustomerSuccess";}}@RequestMapping(method = RequestMethod.GET)public String initForm(ModelMap model){Customer cust = new Customer();//Make "Spring MVC" as default checked valuecust.setFavFramework(new String []{"Spring MVC"});//Make "Make" as default radio button selected valuecust.setSex("M");//make "Hibernate" as the default java skills selectioncust.setJavaSkills("Hibernate");//initilize a hidden valuecust.setSecretValue("I'm hidden value");//command objectmodel.addAttribute("customer", cust);//return form viewreturn "CustomerForm";}@ModelAttribute("webFrameworkList")public List<String> populateWebFrameworkList() {//Data referencing for web framework checkboxesList<String> webFrameworkList = new ArrayList<String>();webFrameworkList.add("Spring MVC");webFrameworkList.add("Struts 1");webFrameworkList.add("Struts 2");webFrameworkList.add("JSF");webFrameworkList.add("Apache Wicket");return webFrameworkList;}@InitBinderpublic void initBinder(WebDataBinder binder) {SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));}@ModelAttribute("numberList")public List<String> populateNumberList() {//Data referencing for number radiobuttonsList<String> numberList = new ArrayList<String>();numberList.add("Number 1");numberList.add("Number 2");numberList.add("Number 3");numberList.add("Number 4");numberList.add("Number 5");return numberList;}@ModelAttribute("javaSkillsList")public Map<String,String> populateJavaSkillList() {//Data referencing for java skills list boxMap<String,String> javaSkill = new LinkedHashMap<String,String>();javaSkill.put("Hibernate", "Hibernate");javaSkill.put("Spring", "Spring");javaSkill.put("Apache Wicket", "Apache Wicket");javaSkill.put("Struts", "Struts");return javaSkill;}@ModelAttribute("countryList")public Map<String,String> populateCountryList() {//Data referencing for java skills list boxMap<String,String> country = new LinkedHashMap<String,String>();country.put("US", "United Stated");country.put("CHINA", "China");country.put("SG", "Singapore");country.put("MY", "Malaysia");return country;}
}
要使注释工作,您必须在 Spring 中启用组件自动扫描特性。
<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/beans http://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.controller" /><bean class="com.mkyong.customer.validator.CustomerValidator" /><!-- Register the Customer.properties --><bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basename" value="com/mkyong/customer/properties/Customer" /></bean><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>
</beans>
下载源代码
Download it – SpringMVC-Form-Handling-Annotation-Example.zip (12KB)
参考
- spring 2.5 中带注释的 web mvc 控制器
- Spring MVC 表单处理示例–XML 版本
- Spring MVC hello world 注释示例
- Spring MVC multi action controller 注释示例
Tags : annotation form spring mvc
Spring MVC 表单处理示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-form-handling-example/
在本教程中,我们将向您展示一个 Spring MVC 表单处理项目来完成以下工作:
- 表单值绑定 JSP 和模型。
- 表单验证并显示错误消息。
- 形成 POST/REDIRECT/GET 模式,并将消息添加到 flash 属性。
- CRUD 操作,用一个 HTML 表单添加、获取、更新和删除。
使用的技术:
- 弹簧 4.1.6 释放
- maven3
- 自举 3
- HSQLDB 驱动程序 2.3.2
- 回溯 1.1.3
- JDK 1.7
- JSTL 1.2
- Eclipse IDE
一个简单的用户管理项目,你可以通过 HTML 表单列出、创建、更新和删除一个用户。您还将看到如何执行表单验证并有条件地显示错误消息。该项目使用 Bootstrap 3 进行设计,数据存储在 HSQL 嵌入式数据库中。
URI 结构:
| 上呼吸道感染 | 方法 | 行动 |
| /用户 | 得到 | 列表,显示所有用户 |
| /用户 | 邮政 | 保存或更新用户 |
| /users/{id} | 得到 | 显示用户{id} |
| /用户/添加 | 得到 | 显示添加用户表单 |
| /users/{id}/update | 得到 | 显示{id}的更新用户表单 |
| /users/{id}/delete | 邮政 | 删除用户{id} |
Note
In the old days, before Spring 3.0, we use [SimpleFormController](http://web.archive.org/web/20190303052227/http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/web/portlet/mvc/SimpleFormController.html)
to do the form handling. As Spring 3.0, this class is deprecated in favor of Spring annotated @Controller.
Spring MVC 表单绑定
在开始本教程之前,您需要了解 Spring MVC 表单绑定是如何工作的。
1.1 在 controller 中,将对象添加到模型属性中。
@RequestMapping(value = "/users/add", method = RequestMethod.GET)public String showAddUserForm(Model model) {User user = new User();model.addAttribute("userForm", user);//...}
1.2 在 HTML 表单中,你使用spring:form
标签,通过modelAttribute
绑定控制器对象。
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%><form:form method="post" modelAttribute="userForm" action="${userActionUrl}"><form:input path="name" type="text" /> <!-- bind to user.name--><form:errors path="name" /></form:form>
1.3 当 HTML 表单为“POST”时,通过@ModelAttribute
获取值。
@RequestMapping(value = "/users", method = RequestMethod.POST)
public String saveOrUpdateUser(@ModelAttribute("userForm") User user,BindingResult result, Model model) {//...
}
完成了。让我们开始教程。
1.项目目录
这是最终的项目目录结构。标准的 Maven 项目。
## 2.项目相关性
开发一个 Spring MVC 项目,需要spring-webmvc
。
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.form</groupId><artifactId>spring-mvc-form</artifactId><packaging>war</packaging><version>1.0-SNAPSHOT</version><name>SpringMVC + Form Handling Example</name><properties><jdk.version>1.7</jdk.version><spring.version>4.1.6.RELEASE</spring.version><hsqldb.version>2.3.2</hsqldb.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><!-- Spring Core --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version><exclusions><exclusion><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId></exclusion></exclusions></dependency><!-- Spring Web --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!-- Spring JDBC --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><!-- HyperSQL DB --><dependency><groupId>org.hsqldb</groupId><artifactId>hsqldb</artifactId><version>${hsqldb.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><!-- jstl --><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>${jstl.version}</version></dependency><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>/spring-mvc-form</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>spring-mvc-form</wtpContextName></configuration></plugin></plugins></build>
</project>
3.控制器
Spring @Controller
类向你展示如何通过@ModelAttribute
绑定表单值,添加表单验证器,将消息添加到 flash 属性中,填充下拉列表和复选框的值等等。阅读评论,不言自明。
UserController.java
package com.mkyong.form.web;import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
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;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;import com.mkyong.form.model.User;
import com.mkyong.form.service.UserService;
import com.mkyong.form.validator.UserFormValidator;@Controller
public class UserController {private final Logger logger = LoggerFactory.getLogger(UserController.class);@Autowiredprivate UserService userService;@AutowiredUserFormValidator userFormValidator;//Set a form validator@InitBinderprotected void initBinder(WebDataBinder binder) {binder.setValidator(userFormValidator);}@RequestMapping(value = "/", method = RequestMethod.GET)public String index(Model model) {logger.debug("index()");return "redirect:/users";}// list page@RequestMapping(value = "/users", method = RequestMethod.GET)public String showAllUsers(Model model) {logger.debug("showAllUsers()");model.addAttribute("users", userService.findAll());return "users/list";}// save or update user// 1\. @ModelAttribute bind form value// 2\. @Validated form validator// 3\. RedirectAttributes for flash value@RequestMapping(value = "/users", method = RequestMethod.POST)public String saveOrUpdateUser(@ModelAttribute("userForm") @Validated User user,BindingResult result, Model model, final RedirectAttributes redirectAttributes) {logger.debug("saveOrUpdateUser() : {}", user);if (result.hasErrors()) {populateDefaultModel(model);return "users/userform";} else {// Add message to flash scoperedirectAttributes.addFlashAttribute("css", "success");if(user.isNew()){redirectAttributes.addFlashAttribute("msg", "User added successfully!");}else{redirectAttributes.addFlashAttribute("msg", "User updated successfully!");}userService.saveOrUpdate(user);// POST/REDIRECT/GETreturn "redirect:/users/" + user.getId();// POST/FORWARD/GET// return "user/list";}}// show add user form@RequestMapping(value = "/users/add", method = RequestMethod.GET)public String showAddUserForm(Model model) {logger.debug("showAddUserForm()");User user = new User();// set default valueuser.setName("mkyong123");user.setEmail("test@gmail.com");user.setAddress("abc 88");user.setNewsletter(true);user.setSex("M");user.setFramework(new ArrayList<String>(Arrays.asList("Spring MVC", "GWT")));user.setSkill(new ArrayList<String>(Arrays.asList("Spring", "Grails", "Groovy")));user.setCountry("SG");user.setNumber(2);model.addAttribute("userForm", user);populateDefaultModel(model);return "users/userform";}// show update form@RequestMapping(value = "/users/{id}/update", method = RequestMethod.GET)public String showUpdateUserForm(@PathVariable("id") int id, Model model) {logger.debug("showUpdateUserForm() : {}", id);User user = userService.findById(id);model.addAttribute("userForm", user);populateDefaultModel(model);return "users/userform";}// delete user@RequestMapping(value = "/users/{id}/delete", method = RequestMethod.POST)public String deleteUser(@PathVariable("id") int id, final RedirectAttributes redirectAttributes) {logger.debug("deleteUser() : {}", id);userService.delete(id);redirectAttributes.addFlashAttribute("css", "success");redirectAttributes.addFlashAttribute("msg", "User is deleted!");return "redirect:/users";}// show user@RequestMapping(value = "/users/{id}", method = RequestMethod.GET)public String showUser(@PathVariable("id") int id, Model model) {logger.debug("showUser() id: {}", id);User user = userService.findById(id);if (user == null) {model.addAttribute("css", "danger");model.addAttribute("msg", "User not found");}model.addAttribute("user", user);return "users/show";}private void populateDefaultModel(Model model) {List<String> frameworksList = new ArrayList<String>();frameworksList.add("Spring MVC");frameworksList.add("Struts 2");frameworksList.add("JSF 2");frameworksList.add("GWT");frameworksList.add("Play");frameworksList.add("Apache Wicket");model.addAttribute("frameworkList", frameworksList);Map<String, String> skill = new LinkedHashMap<String, String>();skill.put("Hibernate", "Hibernate");skill.put("Spring", "Spring");skill.put("Struts", "Struts");skill.put("Groovy", "Groovy");skill.put("Grails", "Grails");model.addAttribute("javaSkillList", skill);List<Integer> numbers = new ArrayList<Integer>();numbers.add(1);numbers.add(2);numbers.add(3);numbers.add(4);numbers.add(5);model.addAttribute("numberList", numbers);Map<String, String> country = new LinkedHashMap<String, String>();country.put("US", "United Stated");country.put("CN", "China");country.put("SG", "Singapore");country.put("MY", "Malaysia");model.addAttribute("countryList", country);}}
4.表单验证器
4.1 Spring 验证器示例。
UserFormValidator.java
package com.mkyong.form.validator;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;import com.mkyong.form.model.User;
import com.mkyong.form.service.UserService;@Component
public class UserFormValidator implements Validator {@Autowired@Qualifier("emailValidator")EmailValidator emailValidator;@AutowiredUserService userService;@Overridepublic boolean supports(Class<?> clazz) {return User.class.equals(clazz);}@Overridepublic void validate(Object target, Errors errors) {User user = (User) target;ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "NotEmpty.userForm.name");ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "NotEmpty.userForm.email");ValidationUtils.rejectIfEmptyOrWhitespace(errors, "address", "NotEmpty.userForm.address");ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "NotEmpty.userForm.password");ValidationUtils.rejectIfEmptyOrWhitespace(errors, "confirmPassword","NotEmpty.userForm.confirmPassword");ValidationUtils.rejectIfEmptyOrWhitespace(errors, "sex", "NotEmpty.userForm.sex");ValidationUtils.rejectIfEmptyOrWhitespace(errors, "country", "NotEmpty.userForm.country");if(!emailValidator.valid(user.getEmail())){errors.rejectValue("email", "Pattern.userForm.email");}if(user.getNumber()==null || user.getNumber()<=0){errors.rejectValue("number", "NotEmpty.userForm.number");}if(user.getCountry().equalsIgnoreCase("none")){errors.rejectValue("country", "NotEmpty.userForm.country");}if (!user.getPassword().equals(user.getConfirmPassword())) {errors.rejectValue("confirmPassword", "Diff.userform.confirmPassword");}if (user.getFramework() == null || user.getFramework().size() < 2) {errors.rejectValue("framework", "Valid.userForm.framework");}if (user.getSkill() == null || user.getSkill().size() < 3) {errors.rejectValue("skill", "Valid.userForm.skill");}}}
validation.properties
NotEmpty.userForm.name = Name is required!
NotEmpty.userForm.email = Email is required!
NotEmpty.userForm.address = Address is required!
NotEmpty.userForm.password = Password is required!
NotEmpty.userForm.confirmPassword = Confirm password is required!
NotEmpty.userForm.sex = Sex is required!
NotEmpty.userForm.number = Number is required!
NotEmpty.userForm.country = Country is required!
Valid.userForm.framework = Please select at least two frameworks!
Valid.userForm.skill = Please select at least three skills!
Diff.userform.confirmPassword = Passwords do not match, please retype!
Pattern.userForm.email = Invalid Email format!
要运行 Spring 验证器,通过@InitBinder
添加验证器,并用@Validated
注释模型
@InitBinder
protected void initBinder(WebDataBinder binder) {binder.setValidator(userFormValidator);
}@RequestMapping(value = "/users", method = RequestMethod.POST)
public String saveOrUpdateUser(... @Validated User user,...) {//...}
或者手动运行。
@RequestMapping(value = "/users", method = RequestMethod.POST)
public String saveOrUpdateUser(... User user,...) {userFormValidator.validate(user, result); //...
}
5.HTML 表单
所有的 HTML 表单都是 css 样式,使用 Bootstrap 框架,并使用 Spring form 标签进行显示和表单绑定。
5.1 用户列表。
list.jsp
<%@ page session="false"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%><!DOCTYPE html>
<html lang="en"><jsp:include page="../fragments/header.jsp" /><body><div class="container"><c:if test="${not empty msg}"><div class="alert alert-${css} alert-dismissible" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button><strong>${msg}</strong></div></c:if><h1>All Users</h1><table class="table table-striped"><thead><tr><th>#ID</th><th>Name</th><th>Email</th><th>framework</th><th>Action</th></tr></thead><c:forEach var="user" items="${users}"><tr><td>${user.id}</td><td>${user.name}</td><td>${user.email}</td><td><c:forEach var="framework" items="${user.framework}" varStatus="loop">${framework}<c:if test="${not loop.last}">,</c:if></c:forEach></td><td><spring:url value="/users/${user.id}" var="userUrl" /><spring:url value="/users/${user.id}/delete" var="deleteUrl" /> <spring:url value="/users/${user.id}/update" var="updateUrl" /><button class="btn btn-info" onclick="location.href='${userUrl}'">Query</button><button class="btn btn-primary" onclick="location.href='${updateUrl}'">Update</button><button class="btn btn-danger" onclick="this.disabled=true;post('${deleteUrl}')">Delete</button></td></tr></c:forEach></table></div><jsp:include page="../fragments/footer.jsp" /></body>
</html>
show.jsp
<%@ page session="false"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%><!DOCTYPE html>
<html lang="en"><jsp:include page="../fragments/header.jsp" /><div class="container"><c:if test="${not empty msg}"><div class="alert alert-${css} alert-dismissible" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button><strong>${msg}</strong></div></c:if><h1>User Detail</h1><br /><div class="row"><label class="col-sm-2">ID</label><div class="col-sm-10">${user.id}</div></div><div class="row"><label class="col-sm-2">Name</label><div class="col-sm-10">${user.name}</div></div><div class="row"><label class="col-sm-2">Email</label><div class="col-sm-10">${user.email}</div></div><div class="row"><label class="col-sm-2">Address</label><div class="col-sm-10">${user.address}</div></div><div class="row"><label class="col-sm-2">Newsletter</label><div class="col-sm-10">${user.newsletter}</div></div><div class="row"><label class="col-sm-2">Web Frameworks</label><div class="col-sm-10">${user.framework}</div></div><div class="row"><label class="col-sm-2">Sex</label><div class="col-sm-10">${user.sex}</div></div><div class="row"><label class="col-sm-2">Number</label><div class="col-sm-10">${user.number}</div></div><div class="row"><label class="col-sm-2">Country</label><div class="col-sm-10">${user.country}</div></div><div class="row"><label class="col-sm-2">Skill</label><div class="col-sm-10">${user.skill}</div></div></div><jsp:include page="../fragments/footer.jsp" /></body>
</html>
userform.jsp
<%@ page session="false"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%><!DOCTYPE html>
<html lang="en"><jsp:include page="../fragments/header.jsp" /><div class="container"><c:choose><c:when test="${userForm['new']}"><h1>Add User</h1></c:when><c:otherwise><h1>Update User</h1></c:otherwise></c:choose><br /><spring:url value="/users" var="userActionUrl" /><form:form class="form-horizontal" method="post" modelAttribute="userForm" action="${userActionUrl}"><form:hidden path="id" /><spring:bind path="name"><div class="form-group ${status.error ? 'has-error' : ''}"><label class="col-sm-2 control-label">Name</label><div class="col-sm-10"><form:input path="name" type="text" class="form-control" id="name" placeholder="Name" /><form:errors path="name" class="control-label" /></div></div></spring:bind><spring:bind path="email"><div class="form-group ${status.error ? 'has-error' : ''}"><label class="col-sm-2 control-label">Email</label><div class="col-sm-10"><form:input path="email" class="form-control" id="email" placeholder="Email" /><form:errors path="email" class="control-label" /></div></div></spring:bind><spring:bind path="password"><div class="form-group ${status.error ? 'has-error' : ''}"><label class="col-sm-2 control-label">Password</label><div class="col-sm-10"><form:password path="password" class="form-control" id="password" placeholder="password" /><form:errors path="password" class="control-label" /></div></div></spring:bind><spring:bind path="confirmPassword"><div class="form-group ${status.error ? 'has-error' : ''}"><label class="col-sm-2 control-label">confirm Password</label><div class="col-sm-10"><form:password path="confirmPassword" class="form-control" id="password" placeholder="password" /><form:errors path="confirmPassword" class="control-label" /></div></div></spring:bind><spring:bind path="address"><div class="form-group ${status.error ? 'has-error' : ''}"><label class="col-sm-2 control-label">Address</label><div class="col-sm-10"><form:textarea path="address" rows="5" class="form-control" id="address" placeholder="address" /><form:errors path="address" class="control-label" /></div></div></spring:bind><spring:bind path="newsletter"><div class="form-group ${status.error ? 'has-error' : ''}"><label class="col-sm-2 control-label">Newsletter</label><div class="col-sm-10"><div class="checkbox"><label> <form:checkbox path="newsletter" id="newsletter" /></label><form:errors path="newsletter" class="control-label" /></div></div></div></spring:bind><spring:bind path="framework"><div class="form-group ${status.error ? 'has-error' : ''}"><label class="col-sm-2 control-label">Web Frameworks</label><div class="col-sm-10"><form:checkboxes path="framework" items="${frameworkList}" element="label class='checkbox-inline'" /><br /><form:errors path="framework" class="control-label" /></div></div></spring:bind><spring:bind path="sex"><div class="form-group ${status.error ? 'has-error' : ''}"><label class="col-sm-2 control-label">Sex</label><div class="col-sm-10"><label class="radio-inline"> <form:radiobutton path="sex" value="M" /> Male</label> <label class="radio-inline"> <form:radiobutton path="sex" value="F" /> Female</label> <br /><form:errors path="sex" class="control-label" /></div></div></spring:bind><spring:bind path="number"><div class="form-group ${status.error ? 'has-error' : ''}"><label class="col-sm-2 control-label">Number</label><div class="col-sm-10"><form:radiobuttons path="number" items="${numberList}" element="label class='radio-inline'" /><br /><form:errors path="number" class="control-label" /></div></div></spring:bind><spring:bind path="country"><div class="form-group ${status.error ? 'has-error' : ''}"><label class="col-sm-2 control-label">Country</label><div class="col-sm-5"><form:select path="country" class="form-control"><form:option value="NONE" label="--- Select ---" /><form:options items="${countryList}" /></form:select><form:errors path="country" class="control-label" /></div><div class="col-sm-5"></div></div></spring:bind><spring:bind path="skill"><div class="form-group ${status.error ? 'has-error' : ''}"><label class="col-sm-2 control-label">Java Skills</label><div class="col-sm-5"><form:select path="skill" items="${javaSkillList}" multiple="true" size="5" class="form-control" /><form:errors path="skill" class="control-label" /></div><div class="col-sm-5"></div></div></spring:bind><div class="form-group"><div class="col-sm-offset-2 col-sm-10"><c:choose><c:when test="${userForm['new']}"><button type="submit" class="btn-lg btn-primary pull-right">Add</button></c:when><c:otherwise><button type="submit" class="btn-lg btn-primary pull-right">Update</button></c:otherwise></c:choose></div></div></form:form></div><jsp:include page="../fragments/footer.jsp" /></body>
</html>
6.数据库的东西
6.1 创建一个表,并插入一些测试数据。
create-db.sql
CREATE TABLE users (id INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 100, INCREMENT BY 1) PRIMARY KEY,name VARCHAR(30),email VARCHAR(50),address VARCHAR(255),password VARCHAR(20),newsletter BOOLEAN,framework VARCHAR(500),sex VARCHAR(1),NUMBER INTEGER,COUNTRY VARCHAR(10),SKILL VARCHAR(500)
);
insert-data.sql
INSERT INTO users (name, email, framework) VALUES ('mkyong', 'mkyong@gmail.com', 'Spring MVC, GWT');
INSERT INTO users (name, email) VALUES ('alex', 'alex@yahoo.com', 'Spring MVC, GWT');
INSERT INTO users (name, email) VALUES ('joel', 'joel@gmail.com', 'Spring MVC, GWT');
6.2 启动一个 HSQLDB 嵌入式数据库,创建一个数据源和 jdbcTemplate。
SpringDBConfig.java
package com.mkyong.form.config;import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;@Configuration
public class SpringDBConfig {@AutowiredDataSource dataSource;@Beanpublic NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {return new NamedParameterJdbcTemplate(dataSource);}@Beanpublic DataSource getDataSource() {EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();EmbeddedDatabase db = builder.setName("testdb").setType(EmbeddedDatabaseType.HSQL).addScript("db/sql/create-db.sql").addScript("db/sql/insert-data.sql").build();return db;}}
6.3 用户对象。
user.java
package com.mkyong.form.model;import java.util.List;public class User {// form:hidden - hidden valueInteger id;// form:input - textboxString name;// form:input - textboxString email;// form:textarea - textareaString address;// form:input - passwordString password;// form:input - passwordString confirmPassword;// form:checkbox - single checkboxboolean newsletter;// form:checkboxes - multiple checkboxesList<String> framework;// form:radiobutton - radio buttonString sex;// form:radiobuttons - radio buttonInteger number;// form:select - form:option - dropdown - single selectString country;// form:select - multiple=true - dropdown - multiple selectList<String> skill;//Check if this is for New of Updatepublic boolean isNew() {return (this.id == null);}//...}
7.服务和一体行动
UserService.java
package com.mkyong.form.service;import java.util.List;
import com.mkyong.form.model.User;public interface UserService {User findById(Integer id);List<User> findAll();void saveOrUpdate(User user);void delete(int id);}
UserServiceImpl.java
package com.mkyong.form.service;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import com.mkyong.form.dao.UserDao;
import com.mkyong.form.model.User;@Service("userService")
public class UserServiceImpl implements UserService {UserDao userDao;@Autowiredpublic void setUserDao(UserDao userDao) {this.userDao = userDao;}@Overridepublic User findById(Integer id) {return userDao.findById(id);}@Overridepublic List<User> findAll() {return userDao.findAll();}@Overridepublic void saveOrUpdate(User user) {if (findById(user.getId())==null) {userDao.save(user);} else {userDao.update(user);}}@Overridepublic void delete(int id) {userDao.delete(id);}}
UserDao.java
package com.mkyong.form.dao;import java.util.List;import com.mkyong.form.model.User;public interface UserDao {User findById(Integer id);List<User> findAll();void save(User user);void update(User user);void delete(Integer id);}
UserDaoImpl.java
package com.mkyong.form.dao;import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;import com.mkyong.form.model.User;@Repository
public class UserDaoImpl implements UserDao {NamedParameterJdbcTemplate namedParameterJdbcTemplate;@Autowiredpublic void setNamedParameterJdbcTemplate(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;}@Overridepublic User findById(Integer id) {Map<String, Object> params = new HashMap<String, Object>();params.put("id", id);String sql = "SELECT * FROM users WHERE id=:id";User result = null;try {result = namedParameterJdbcTemplate.queryForObject(sql, params, new UserMapper());} catch (EmptyResultDataAccessException e) {// do nothing, return null}return result;}@Overridepublic List<User> findAll() {String sql = "SELECT * FROM users";List<User> result = namedParameterJdbcTemplate.query(sql, new UserMapper());return result;}@Overridepublic void save(User user) {KeyHolder keyHolder = new GeneratedKeyHolder();String sql = "INSERT INTO USERS(NAME, EMAIL, ADDRESS, PASSWORD, NEWSLETTER, FRAMEWORK, SEX, NUMBER, COUNTRY, SKILL) "+ "VALUES ( :name, :email, :address, :password, :newsletter, :framework, :sex, :number, :country, :skill)";namedParameterJdbcTemplate.update(sql, getSqlParameterByModel(user), keyHolder);user.setId(keyHolder.getKey().intValue());}@Overridepublic void update(User user) {String sql = "UPDATE USERS SET NAME=:name, EMAIL=:email, ADDRESS=:address, " + "PASSWORD=:password, NEWSLETTER=:newsletter, FRAMEWORK=:framework, "+ "SEX=:sex, NUMBER=:number, COUNTRY=:country, SKILL=:skill WHERE id=:id";namedParameterJdbcTemplate.update(sql, getSqlParameterByModel(user));}@Overridepublic void delete(Integer id) {String sql = "DELETE FROM USERS WHERE id= :id";namedParameterJdbcTemplate.update(sql, new MapSqlParameterSource("id", id));}private SqlParameterSource getSqlParameterByModel(User user) {MapSqlParameterSource paramSource = new MapSqlParameterSource();paramSource.addValue("id", user.getId());paramSource.addValue("name", user.getName());paramSource.addValue("email", user.getEmail());paramSource.addValue("address", user.getAddress());paramSource.addValue("password", user.getPassword());paramSource.addValue("newsletter", user.isNewsletter());// join StringparamSource.addValue("framework", convertListToDelimitedString(user.getFramework()));paramSource.addValue("sex", user.getSex());paramSource.addValue("number", user.getNumber());paramSource.addValue("country", user.getCountry());paramSource.addValue("skill", convertListToDelimitedString(user.getSkill()));return paramSource;}private static final class UserMapper implements RowMapper<User> {public User mapRow(ResultSet rs, int rowNum) throws SQLException {User user = new User();user.setId(rs.getInt("id"));user.setName(rs.getString("name"));user.setEmail(rs.getString("email"));user.setFramework(convertDelimitedStringToList(rs.getString("framework")));user.setAddress(rs.getString("address"));user.setCountry(rs.getString("country"));user.setNewsletter(rs.getBoolean("newsletter"));user.setNumber(rs.getInt("number"));user.setPassword(rs.getString("password"));user.setSex(rs.getString("sex"));user.setSkill(convertDelimitedStringToList(rs.getString("skill")));return user;}}private static List<String> convertDelimitedStringToList(String delimitedString) {List<String> result = new ArrayList<String>();if (!StringUtils.isEmpty(delimitedString)) {result = Arrays.asList(StringUtils.delimitedListToStringArray(delimitedString, ","));}return result;}private String convertListToDelimitedString(List<String> list) {String result = "";if (list != null) {result = StringUtils.arrayToCommaDelimitedString(list.toArray());}return result;}}
8.弹簧配置
混合 Spring XML 和 JavaConfig。
SpringWebConfig.java
package com.mkyong.form.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
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
@Configuration
@ComponentScan({ "com.mkyong.form.web", "com.mkyong.form.service", "com.mkyong.form.dao","com.mkyong.form.exception", "com.mkyong.form.validator" })
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;}@Beanpublic ResourceBundleMessageSource messageSource() {ResourceBundleMessageSource rb = new ResourceBundleMessageSource();rb.setBasenames(new String[] { "messages/messages", "messages/validation" });return rb;}}
spring-web-servlet.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.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- Scan the JavaConfig --><context:component-scan base-package="com.mkyong.form.config" /></beans>
web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"version="3.0"><display-name>Spring3 MVC Application</display-name><servlet><servlet-name>spring-web</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>spring-web</servlet-name><url-pattern>/</url-pattern></servlet-mapping><error-page><error-code>500</error-code><location>/WEB-INF/views/jsp/error.jsp</location></error-page><error-page><error-code>404</error-code><location>/WEB-INF/views/jsp/error.jsp</location></error-page><error-page><location>/WEB-INF/views/jsp/error.jsp</location></error-page></web-app>
9.演示
下载项目并键入mvn jetty:run
$ mvn jetty:run
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building SpringMVC + Form Handling Example 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
//...
[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 10 seconds.
9.1 列出所有用户。http://localhost:8080/spring-MVC-form/users
9.2 添加用户。http://localhost:8080/spring-MVC-form/users/add
9.3 表单验证。
9.4 新增用户。http://localhost:8080/spring-MVC-form/users
9.5 删除用户。http://localhost:8080/spring-MVC-form/users/104/delete
下载源代码
Download it - spring4-form-handle-example.zip (80 kb)Github - TBD
参考
- 使用 Spring 的表单标签库
- Spring MVC 3 验证
- RedirectAttributes JavaDoc
form handling spring mvc
Spring MVC 处理程序拦截器示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-handler-interceptors-example/
Spring MVC 允许您通过处理程序拦截器来拦截 web 请求。处理程序拦截器必须实现 HandlerInterceptor 接口,该接口包含三个方法:
- preHandle()–在处理程序执行前调用,返回一个布尔值,“true”:继续处理程序执行链;“false”,停止执行链并返回。
- post handle()–在处理程序执行后调用,允许在将 ModelAndView 对象呈现到视图页面之前对其进行操作。
- after completion()–在完成请求完成后调用。很少使用,找不到任何用例。
在本教程中,您将创建两个处理程序拦截器来展示 HandlerInterceptor 的用法。
- execute time interceptor–拦截 web 请求,记录控制器执行时间。
- 维护拦截器–拦截 web 请求,检查当前时间是否在维护时间之间,如果是,则重定向到维护页面。
Note
It’s recommended to extend the HandlerInterceptorAdapter for the convenient default implementations.
1.ExecuteTimeInterceptor
截取控制器执行前后的时间,记录执行的开始和结束时间,保存到已有的截取控制器的 modelAndView 中,以便以后显示。
文件:ExecuteTimeInterceptor.java
package com.mkyong.common.interceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.log4j.Logger;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;public class ExecuteTimeInterceptor extends HandlerInterceptorAdapter{private static final Logger logger = Logger.getLogger(ExecuteTimeInterceptor.class);//before the actual handler will be executedpublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {long startTime = System.currentTimeMillis();request.setAttribute("startTime", startTime);return true;}//after the handler is executedpublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception {long startTime = (Long)request.getAttribute("startTime");long endTime = System.currentTimeMillis();long executeTime = endTime - startTime;//modified the exisitng modelAndViewmodelAndView.addObject("executeTime",executeTime);//log itif(logger.isDebugEnabled()){logger.debug("[" + handler + "] executeTime : " + executeTime + "ms");}}
}
2.维护拦截器
在控制器执行前拦截,检查当前时间是否在维护时间之间,如果是则重定向到维护页面;否则继续执行链。
文件:MaintenanceInterceptor.java
package com.mkyong.common.interceptor;import java.util.Calendar;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;public class MaintenanceInterceptor extends HandlerInterceptorAdapter{private int maintenanceStartTime;private int maintenanceEndTime;private String maintenanceMapping;public void setMaintenanceMapping(String maintenanceMapping) {this.maintenanceMapping = maintenanceMapping;}public void setMaintenanceStartTime(int maintenanceStartTime) {this.maintenanceStartTime = maintenanceStartTime;}public void setMaintenanceEndTime(int maintenanceEndTime) {this.maintenanceEndTime = maintenanceEndTime;}//before the actual handler will be executedpublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {Calendar cal = Calendar.getInstance();int hour = cal.get(cal.HOUR_OF_DAY);if (hour >= maintenanceStartTime && hour <= maintenanceEndTime) {//maintenance time, send to maintenance pageresponse.sendRedirect(maintenanceMapping);return false;} else {return true;}}
}
3.启用处理程序拦截器
要启用它,请将您的处理程序拦截器类放入处理程序映射“拦截器”属性中。
<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 class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="mappings"><props><prop key="/welcome.htm">welcomeController</prop></props></property><property name="interceptors"><list><ref bean="maintenanceInterceptor" /><ref bean="executeTimeInterceptor" /></list></property></bean><beanclass="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"><property name="interceptors"><list><ref bean="executeTimeInterceptor" /></list></property></bean><bean id="welcomeController" class="com.mkyong.common.controller.WelcomeController" /><bean class="com.mkyong.common.controller.MaintenanceController" /><bean id="executeTimeInterceptor" class="com.mkyong.common.interceptor.ExecuteTimeInterceptor" /><bean id="maintenanceInterceptor" class="com.mkyong.common.interceptor.MaintenanceInterceptor"><property name="maintenanceStartTime" value="23" /><property name="maintenanceEndTime" value="24" /><property name="maintenanceMapping" value="/SpringMVC/maintenance.htm" /></bean><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></beans>
下载源代码
Download it –SpringMVC-HandlerInterceptor-Example.zip (8 KB)
参考
- HandlerInterceptorAdapter 文档
- 处理接收器文档
- ControllerClassNameHandlerMapping 示例
- SimpleUrlHandlerMapping 示例
Tags : interceptor spring mvc
用 AbstractWizardFormController 处理多页表单
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-handling-multipage-forms-with-abstractwizardformcontroller/
在上一个 Spring MVC 表单处理示例中,我们将向您介绍如何使用 SimpleFormController 来处理单页表单提交,这非常简单明了。
但是,有时,您可能需要处理"向导表单,这需要将表单处理成多页,并要求用户逐页填写表单。在这种向导表单情况下,主要关心的是如何存储模型数据(由用户填写的数据)并将其带到多个页面上?
SAbstractWizardFormController
幸运的是,Spring MVC 自带了AbstractWizardFormController类来轻松处理这个向导表单。在本教程中,我们将向您展示如何使用AbstractWizardFormController类来跨多个页面存储和携带表单数据,应用验证并在最后一页显示表单数据。
1.向导表单页面
本演示共 5 页,按以下顺序进行:
[User] --> WelcomePage --> Page1 --> Page2 --> Page3 --> ResultPage
使用AbstractWizardFormController,页面顺序由提交按钮的“名称”决定:
- _finish:完成向导表单。
- _cancel:取消向导表单。
- _targetx:移动到目标页面,其中 x 是从零开始的页面索引。例如 _target0 、 _target1 等。
1。WelcomePage.jsp
一个欢迎页面,带有一个超链接来启动向导表单过程。
<html>
<body><h2>Handling multipage forms in Spring MVC</h2>Click here to start playing -<a href="user.htm">AbstractWizardFormController example</a>
</body>
</html>
2。Page1Form.jsp
第 1 页,有一个“用户名”文本框,显示错误信息(如果有的话),并包含 2 个提交按钮,其中:
- _ target 1–移至第 2 页。
- _ cancel–取消向导表单流程,并将其移至取消页面
<%@ 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>Page1Form.jsp</h2><form:form method="POST" commandName="userForm"><form:errors path="*" cssClass="errorblock" element="div" /><table><tr><td>Username :</td><td><form:input path="userName" /></td><td><form:errors path="userName" cssClass="error" /></td></tr><tr><tr><td colspan="3"><input type="submit" value="Next"name="_target1" /> <input type="submit" value="Cancel"name="_cancel" /></td></tr></table></form:form></body>
</html>
3。Page2Form.jsp
第 2 页,有一个“密码”字段,显示错误信息(如果有的话),并包含 3 个提交按钮,其中:
- _ target 0–移至第 1 页。
- _ target 2–移至第 3 页。
- _ cancel–取消向导表单流程,并将其移至取消页面
<%@ 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>Page2Form.jsp</h2><form:form method="POST" commandName="userForm"><form:errors path="*" cssClass="errorblock" element="div" /><table><tr><td>Password :</td><td><form:password path="password" /></td><td><form:errors path="password" cssClass="error" /></td></tr><tr><tr><td colspan="3"><input type="submit" value="Previous"name="_target0" /> <input type="submit" value="Next"name="_target2" /> <input type="submit" value="Cancel"name="_cancel" /></td></tr></table></form:form></body>
</html>
4。Page3Form.jsp
第 3 页,有一个“备注”文本框,显示错误信息(如果有),并包含 3 个提交按钮,其中:
- _ target 1–移至第 2 页。
- _ finish–完成向导表单流程,并将其移至完成页面。
- _ cancel–取消向导表单流程,并将其移至取消页面。
<%@ 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>Page3Form.jsp</h2><form:form method="POST" commandName="userForm"><form:errors path="*" cssClass="errorblock" element="div" /><table><tr><td>Remark :</td><td><form:input path="remark" /></td><td><form:errors path="remark" cssClass="error" /></td></tr><tr><tr><td colspan="3"><input type="submit" value="Previous"name="_target1" /> <input type="submit" value="Finish"name="_finish" /> <input type="submit" value="Cancel"name="_cancel" /></td></tr></table></form:form></body>
</html>
5。ResultForm.jsp
显示前 3 页收集的所有表单数据。
<html>
<body><h2>ResultForm.jsp</h2><table><tr><td>UserName :</td><td>${user.userName}</td></tr><tr><td>Password :</td><td>${user.password}</td></tr><tr><td>Remark :</td><td>${user.remark}</td></tr></table></body>
</html>
2.模型
创建一个模型类来存储表单数据。
文件:User.java
package com.mkyong.common.model;public class User{String userName;String password;String remark;//getter and setter methods
}
3.AbstractWizardFormController
扩展AbstractWizardFormController,只需覆盖以下方法
- process finish–当用户点击名为 _finish 的提交按钮时触发。
- process cancel–当用户点击名为 _cancel 的提交按钮时触发。
- formBackingObject–使用“User”模型类将所有表单数据存储在多个页面中。
文件:UserController.java
package com.mkyong.common.controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractWizardFormController;
import com.mkyong.common.model.User;
import com.mkyong.common.validator.UserValidator;public class UserController extends AbstractWizardFormController{public UserController(){setCommandName("userForm");}@Overrideprotected Object formBackingObject(HttpServletRequest request)throws Exception {return new User();}@Overrideprotected ModelAndView processFinish(HttpServletRequest request,HttpServletResponse response, Object command, BindException errors)throws Exception {//Get the data from command objectUser user = (User)command;System.out.println(user);//where is the finish page?return new ModelAndView("ResultForm", "user", user);}@Overrideprotected ModelAndView processCancel(HttpServletRequest request,HttpServletResponse response, Object command, BindException errors)throws Exception {//where is the cancel page?return new ModelAndView("WelcomePage");}
}
一个简单的控制器返回一个" WelcomePage "视图。
文件:WelcomeController.java
package com.mkyong.common.controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;public class WelcomeController extends AbstractController{@Overrideprotected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("WelcomePage");}}
4.多页/向导表单验证
在SimpleFormController
中,创建一个验证器类,将所有的验证逻辑放在 validate() 方法中,并将验证器装饰性地注册到简单表单控制器中。
但是,在AbstractWizardFormController中有点不同。首先,创建一个验证器类,以及每个页面的验证方法,如下所示:
文件:UserValidator.java
package com.mkyong.common.validator;import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import com.mkyong.common.model.User;public class UserValidator implements Validator{@Overridepublic boolean supports(Class clazz) {//just validate the User instancesreturn User.class.isAssignableFrom(clazz);}//validate page 1, userNamepublic void validatePage1Form(Object target, Errors errors) {ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName","required.userName", "Field name is required.");}//validate page 2, passwordpublic void validatePage2Form(Object target, Errors errors) {ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password","required.password", "Field name is required.");}//validate page 3, remarkpublic void validatePage3Form(Object target, Errors errors) {ValidationUtils.rejectIfEmptyOrWhitespace(errors, "remark","required.remark", "Field name is required.");}@Overridepublic void validate(Object target, Errors errors) {validatePage1Form(target, errors);validatePage2Form(target, errors);validatePage3Form(target, errors);}
}
File:user . Properties–存储错误消息的属性
required.userName = Username is required!
required.password = Password is required!
required.remark = Remark is required!
并且,在向导表单控制器(UserController.java
)中,通过手动调用验证器来覆盖 validatePage() (不再有像简单表单控制器那样的声明)。
见UserController.java的更新版本。
public class UserController extends AbstractWizardFormController{//other methods, see above@Overrideprotected void validatePage(Object command, Errors errors, int page) {UserValidator validator = (UserValidator) getValidator();//page is 0-indexedswitch (page) {case 0: //if page 1 , go validate with validatePage1Formvalidator.validatePage1Form(command, errors);break;case 1: //if page 2 , go validate with validatePage2Formvalidator.validatePage2Form(command, errors);break;case 2: //if page 3 , go validate with validatePage3Formvalidator.validatePage3Form(command, errors);break;}}
}
在 validatePage() 方法中,使用一个“开关函数来确定哪个页面正在调用,并将其与相应的验证器相关联。该页面的索引为 0。
5.弹簧配置
声明向导表单控制器(UserController.java
),按正确的顺序排列所有页面,并注册一个验证器。
<bean class="com.mkyong.common.controller.UserController" ><property name="pages"><list><!-- follow sequence --><value>Page1Form</value> <!-- page1, _target0 --><value>Page2Form</value> <!-- page2, _target1 --><value>Page3Form</value> <!-- page3, _target2 --></list></property><property name="validator"><bean class="com.mkyong.common.validator.UserValidator" /></property></bean>
Note
In the “pages” property, the order of the list value is used to define the sequence of the page in the wizard form.
查看完整示例:
<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 class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.common.controller.WelcomeController" /> <bean class="com.mkyong.common.controller.UserController" ><property name="pages"><list><!-- follow sequence --><value>Page1Form</value> <!-- page1 --><value>Page2Form</value> <!-- page2 --><value>Page3Form</value> <!-- page3 --></list></property><property name="validator"><bean class="com.mkyong.common.validator.UserValidator" /></property></bean><!-- Register User.properties for validation error message --><bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basename" value="User" /></bean><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>
</beans>
5.演示
网址:http://localhost:8080/spring MVC/welcome . htm
1。WelcomePage.jsp,点击链接,移动到 Page1Form.jsp。
2。Page1Form.jsp,包含一个“用户名”文本框和两个按钮:
- “下一步”按钮–移动到 Page2Form.jsp。
- “取消”按钮–移至 WelcomePage.jsp
如果提交表单时“用户名”为空,则显示错误消息。
3。Page2Form.jsp,包含一个“密码”字段和 3 个按钮:
- “上一页”按钮–移至 Page1Form.jsp。
- “下一步”按钮–移动到 Page3Form.jsp。
- “取消”按钮–移至 WelcomePage.jsp。
4。Page3Form.jsp,包含一个“备注”文本框和 3 个按钮:
- “上一页”按钮–移至 Page2Form.jsp。
- “完成”按钮–移动到 ResultForm.jsp。
- “取消”按钮–移至 WelcomePage.jsp。
5。ResultForm.jsp,显示所有表单的数据。
下载源代码
Download it – SpringMVC-MultiPage-Form-Handling-Example.zip (12KB)
参考
- AbstractWizardFormController Javadoc
- Spring MVC 表单处理示例
Tags : spring mvc
Spring MVC hello world 注释示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-hello-world-annotation-example/
Note
This tutorial is based on Spring 2.5.6, quite outdated. Try considering the new tutorials :
- Gradle+Spring 4 MVC Hello World
- Maven+Spring 3 MVC Hello World
在本教程中,我们将采用之前的 Spring MVC hello world 基于 XML 的,并将其转换为基于注释的项目。
使用的技术:
- 弹簧 2.5.6
- JDK 1.6
- maven3
- Eclipse 3.6
1.目录结构
2.专家
Spring 的注释被捆绑在同一个spring-webmvc.jar
中。
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>spring2-mvc-annotation-hello-world</artifactId><packaging>war</packaging><version>1.0-SNAPSHOT</version><name>Spring 2 MVC</name><properties><jdk.version>1.6</jdk.version><spring.version>2.5.6</spring.version><jstl.version>1.2</jstl.version><servletapi.version>2.5</servletapi.version></properties><dependencies><!-- Spring MVC framework --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!-- JSTL --><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>${jstl.version}</version></dependency><!-- for compile only, your container should have this --><dependency><groupId>javax.servlet</groupId><artifactId>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>/spring2</contextPath></webApp></configuration></plugin><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>spring2</wtpContextName></configuration></plugin></plugins></build></project>
3.控制器和处理器映射
现在,您可以使用@Controller
和@RequestMapping
来替换 XML 配置。
- 控制器——控制器类不再需要像 AbstractController 或者SimpleFormController那样扩展基础控制器,只需要简单的用 @Controller 注释对类进行注释即可。
- 处理程序映射——不再声明类似BeanNameUrlHandlerMapping,ControllerClassNameHandlerMapping或SimpleUrlHandlerMapping的处理程序映射,全部替换为标准的@ request Mapping注释。
HelloWorldController.java
package com.mkyong.common.controller;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;@Controller
@RequestMapping("/welcome")
public class HelloWorldController{@RequestMapping(method = RequestMethod.GET)public ModelAndView helloWorld(){ModelAndView model = new ModelAndView("HelloWorldPage");model.addObject("msg", "hello world");return model;}
}
如果在类级别应用@RequestMapping
(可以用多动作控制器在方法级别应用),它需要放一个 RequestMethod 来指示哪个方法处理映射请求。
在这种情况下,如果一个 URI 模式/welcome
被请求,它将映射到这个HelloWorldController
,并用 helloWorld() 方法处理请求。
4.Spring XML 配置
您仍然需要在 XML 文件中配置视图解析器和组件扫描。
/WEB-INF/spring-mvc-config.xml
<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/beans http://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"><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><context:component-scan base-package="com.mkyong.common.controller" /></beans>
5.JSP 页面
用于演示的简单 JSP 页面。
HelloWorldPage.jsp.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body><h1>Spring MVC Hello World Annotation Example</h1><h2>${msg}</h2>
</body>
</html>
6.web.xml
web.xml
<web-app id="WebApp_ID" version="2.4"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"><display-name>Spring Web MVC Application</display-name><servlet><servlet-name>mvc-dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/spring-mvc-config.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>mvc-dispatcher</servlet-name><url-pattern>*.htm</url-pattern></servlet-mapping></web-app>
7.演示
6.1 要运行嵌入式 Jetty,请键入:
$ mvn jetty:run
网址:http://localhost:8080/spring 2/welcome . htm
6.2 导入到 Eclipse IDE 中。
$ mvn eclipse:eclipse
Note
If you compare this Spring MVC annotation-based hello world example with previously XML-based example, you can see that this annotation approach is easier and flexible in wiring the controller class and URL handler mapping, because you do not need to declare the controller class explicitly or extends any particular class.
下载源代码
Download it – spring2-mvc-annotation.zip (15 KB)
参考
- 控制器 Javadoc
- 请求映射 Javadoc
- Spring MVC hello world 基于 XML 的例子
- 弹簧自动扫描组件
Spring MVC hello world 示例(Maven 和百里香叶)
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-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 请求都必须经过这个DispatcherServlet
,DispatcherServlet
会将 web 请求分派给注册的处理程序或组件。
下图演示了 Spring MVC web 应用程序如何处理 web 请求。
图 1.1 :图片复制自 Spring MVC 参考,稍加修改。
注
请参考官方 Spring Web MVC doc 。
2。目录结构
下面是这个项目的标准 Maven 目录结构。
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
http://localhost:8080/spring/hello/mkyong
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 MVC 隐藏值示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-hidden-value-example/
在 Spring MVC 中,可以使用 < form:hidden / > 来渲染一个 HTML 隐藏值字段。举个例子,
<form:hidden path="secretValue" />
它将呈现以下 HTML 代码
<input id="secretValue" name="secretValue" type="hidden" value="I'm hidden value"/>
P.S 假设“ secretValue ”属性包含值“我是隐藏值”。
在本教程中,我们将向您展示如何使用 Spring 的表单标签“ < form:hidden / > ”来呈现一个 HTML 隐藏值。
1.控制器
A SimpleFormController
处理表单隐藏值,用“我是隐藏值,呵呵”初始化隐藏值。
文件:HiddenController.java
package com.mkyong.customer.controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import com.mkyong.customer.model.Customer;public class HiddenController extends SimpleFormController{public HiddenController(){setCommandClass(Customer.class);setCommandName("customerForm");}@Overrideprotected Object formBackingObject(HttpServletRequest request)throws Exception {Customer cust = new Customer();cust.setSecretValue("I'm hidden value, hehe");return cust;}@Overrideprotected ModelAndView onSubmit(HttpServletRequest request,HttpServletResponse response, Object command, BindException errors)throws Exception {Customer customer = (Customer)command;return new ModelAndView("CustomerSuccess","customer",customer);}
}
2.模型
存储窗体隐藏值的客户对象。
文件:Customer.java
package com.mkyong.customer.model;public class Customer{String secretValue;//getter and setter methods
}
3.视角
一个 JSP 页面使用 Spring 的表单标签" < form:hidden / > "来呈现一个 HTML 隐藏值。
文件:CustomerForm.jsp
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<body><h2>Spring's form hidden example</h2><form:form method="POST" commandName="customerForm"><table><tr><td>Hidden value (view source to see it) :</td><td><form:hidden path="secretValue" /></td></tr><tr><td><input type="submit" /></td></tr></table></form:form></body>
</html>
如果表单已提交,则呈现成功页面并显示提交的隐藏值。
文件:CustomerSuccess.jsp
<html>
<body><h2>Spring's form hidden value example</h2>Hidden value : ${customer.secretValue}<br />
</body>
</html>
4.弹簧豆配置
全部链接起来~
<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"><beanclass="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.customer.controller.HiddenController"><property name="formView" value="CustomerForm" /><property name="successView" value="CustomerSuccess" /></bean><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>
</beans>
5.演示
访问页面-http://localhost:8080/SpringMVCForm/hidden . htm
如果表单提交成功,只显示提交的隐藏值。
下载源代码
Download it – SpringMVCForm-HiddenValue-Example.zip (8KB)hidden value spring mvc
spring MVC InternalResourceViewResolver 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-internalresourceviewresolver-example/
在 Spring MVC 中,InternalResourceViewResolver用于根据预定义的 URL 模式解析“内部资源视图”(简单来说,就是最终输出,jsp 或 htmp 页面)。此外,它允许您添加一些预定义的前缀或后缀到视图名称(前缀+视图名称+后缀),并生成最终的视图页面 URL。
What’s internal resource views?
In Spring MVC or any web application, for good practice, it’s always recommended to put the entire views or JSP files under “WEB-INF” folder, to protect it from direct access via manual entered URL. Those views under “WEB-INF” folder are named as internal resource views, as it’s only accessible by the servlet or Spring’s controllers class.
以下示例显示了 InternalResourceViewResolver 的工作方式:
1.控制器
一个返回视图的控制器类,名为“ WelcomePage ”。
//...
public class WelcomeController extends AbstractController{@Overrideprotected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse response) throws Exception {ModelAndView model = new ModelAndView("WelcomePage");return model;}
}
2.InternalResourceViewResolver
在 Spring 的 bean 配置文件中注册InternalResourceViewResolverbean。
<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 class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><!-- Register the bean --><bean class="com.mkyong.common.controller.WelcomeController" /><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></beans>
现在,Spring 将以如下方式解析视图的名称" WelcomePage ":
前缀+视图名+后缀=/we b-INF/pages/WelcomPage。jsp
下载源代码
Download it – SpringMVC-InternalResourceViewResolver-Example.zip (7 KB)
参考
- InternalResourceViewResolver 文档
Spring MVC 国际化示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-internationalization-example/
在 Spring MVC 应用程序中,附带了几个“locale solver”来支持国际化或多语言特性。在本教程中,它显示一个简单的欢迎页面,显示来自属性文件的消息,并根据所选的语言链接更改区域设置。
1.项目文件夹
这个例子的目录结构。
2.属性文件
两个属性文件存储英文和中文信息。
welcome.properties
welcome.springmvc = Happy learning Spring MVC
welcome_zh_CN.properties
welcome.springmvc = \u5feb\u4e50\u5b66\u4e60 Spring MVC
Note
For UTF-8 or non-English characters , you can encode it with native2ascii tool.
3.控制器
控制器类,这里没什么特别的,所有的区域设置都是在 Spring 的 bean 配置文件中配置的。
package com.mkyong.common.controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;public class WelcomeController extends AbstractController{@Overrideprotected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse response) throws Exception {ModelAndView model = new ModelAndView("WelcomePage");return model;}}
4.弹簧配置
为了使 Spring MVC 应用程序支持国际化,注册两个 beans:
1。SessionLocaleResolver
注册一个“SessionLocaleResolver”bean,将其命名为完全相同的字符“ localeResolver ”。它通过从用户的会话中获取预定义的属性来解析区域设置。
Note
If you do not register any “localeResolver”, the default AcceptHeaderLocaleResolver will be used, which resolves the locale by checking the accept-language header in the HTTP request.
2。LocaleChangeInterceptor
注册一个“LocaleChangeInterceptor”拦截器,并将其引用到任何需要支持多语言的处理程序映射。“ paramName 是用于设置区域设置的参数值。
在这种情况下,
- welcome.htm?language = en–从英语属性文件中获取消息。
- welcome.htm?language = zh _ CN–从中文属性文件获取消息。
<bean id="localeChangeInterceptor"class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"><property name="paramName" value="language" /></bean><bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" ><property name="interceptors"><list><ref bean="localeChangeInterceptor" /></list></property></bean>
完整示例见下面
MVC-dispatcher-servlet . 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-2.5.xsd"><bean id="localeResolver"class="org.springframework.web.servlet.i18n.SessionLocaleResolver"><property name="defaultLocale" value="en" /></bean><bean id="localeChangeInterceptor"class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"><property name="paramName" value="language" /></bean><bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" ><property name="interceptors"><list><ref bean="localeChangeInterceptor" /></list></property></bean><!-- Register the bean --><bean class="com.mkyong.common.controller.WelcomeController" /><!-- Register the welcome.properties --><bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basename" value="welcome" /></bean><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></beans>
5.JSP
一个 JSP 页面,包含两个手动更改区域设置的超链接,并使用 spring:message 通过检查当前用户的区域设置来显示来自相应属性文件的消息。
WelcomePage.jsp
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<body>
<h1>Spring MVC internationalization example</h1>Language : <a href="?language=en">English</a>|<a href="?language=zh_CN">Chinese</a><h2>
welcome.springmvc : <spring:message code="welcome.springmvc" text="default text" />
</h2>Current Locale : ${pageContext.response.locale}</body>
</html>
Note
The ${pageContext.response.locale} can be used to display the current user’s locale.Warning
Remember put the “<%@ page contentType=”text/html;charset=UTF-8″ %>” on top of the page, else the page may not able to display the UTF-8 (Chinese) characters properly.
7.演示
通过http://localhost:8080/spring MVC/welcome . htm访问它,通过点击语言的链接更改区域设置。
1。英语区域设置–http://localhost:8080/spring MVC/welcome . htm?语言=en
2。中文区域设置–http://localhost:8080/spring MVC/welcome . htm?语言=zh_CN
下载源代码
Download it – SpringMVC-Internationalization-Example.zip (8KB)
参考
- Spring MVC locale solver 文档
Spring MVC + Log4j 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-log4j-integration-example/
在本教程中,我们将向您展示如何使用 log4j 框架在 Spring MVC web 应用程序中进行日志记录。
使用的技术和工具:
- Log4j 1.2.17
- 弹簧 4.1.6 释放
- maven3
- tomcat6
- 日食开普勒 4.3
Note
By default, Spring (spring-core) is using the JCL (commons-logging) for logging, and the JCL has a runtime discovery algorithm to find out for other logging frameworks in well known places on the project classpath.
要集成 log4j,您需要做的就是:
- 将
log4j.jar
放在项目类路径中。 - 在项目根类路径中创建一个
log4j.properties
或log4j.xml
文件(如果遵循 Maven 标准目录结构,这应该是resources
文件夹)。
1.项目目录
审查最终的项目结构。
2.项目相关性
声明以下依赖项:
pom.xml
<properties><spring.version>4.1.6.RELEASE</spring.version><log4j.version>1.2.17</log4j.version></properties><dependencies><!-- Spring --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!-- Log4j --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency></dependencies>
3.log4j.properties
创建一个log4j.properties
文件,放在resources
中。文件夹,参考上面的项目目录结构。
log4j.properties
# Root logger option
log4j.rootLogger=DEBUG, stdout, file# Redirect log messages to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n# Redirect log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
#outputs to Tomcat home
log4j.appender.file.File=${catalina.home}/logs/myapp.log
log4j.appender.file.MaxFileSize=5MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
4.Spring MVC 控制器+消息日志
返回欢迎页面的简单控制器。此外,它还向您展示了如何使用 log4j 进行日志记录。
WelcomeController.java
package com.mkyong.common.controller;import org.apache.log4j.Logger;
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;@Controller
public class WelcomeController {private static final Logger logger = Logger.getLogger(WelcomeController.class);@RequestMapping(value = "/", method = RequestMethod.GET)public ModelAndView getWelcome() {//logs debug messageif(logger.isDebugEnabled()){logger.debug("getWelcome is executed!");}//logs exceptionlogger.error("This is Error message", new Exception("Testing"));ModelAndView model = new ModelAndView("welcome");model.addObject("msg", "Hello Spring MVC + Log4j");return model;}}
5.演示
5.1 下载源代码,运行内嵌 Jetty 容器的 web app。
$ mvn jetty:run
访问网址:http://localhost:8080/spring-MVC-log4j/
5.2 所有记录信息将显示在控制台中。
log4j.properties
# Redirect log messages to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
Jetty console
2015-06-19 14:10:35 DEBUG WelcomeController:19 - getWelcome is executed!
2015-06-19 14:10:35 ERROR WelcomeController:23 - This is Error message
java.lang.Exception: Testingat com.mkyong.common.controller.WelcomeController.getWelcome(WelcomeController.java:23)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:606)
下载源代码
Download it – spring-mvc-log4j.zip (5 KB)
参考
- 弹簧参考–使用 log4j
- log4j 1.2 官方页面
- log4j hello world 示例
- log4j.properties 示例
Spring MVC + Logback SLF4j 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-logback-slf4j-example/
在本教程中,我们将向您展示如何在 Spring MVC web 应用程序中设置 slf4j 和 logback 。
使用的技术:
- 弹簧 4.1.6 释放
- 回溯 1.1.3
- 腹部 3 度或 2.0 度
- Tomcat 7
- Eclipse 4.4
Note
By default, Spring is using the Jakarta Commons Logging API (JCL), read this.
要设置回退框架,您需要:
- 从
spring-core
中排除commons-logging
- 通过
jcl-over-slf4j
将春季测井从 JCL 桥接到 SLF4j - 将回退作为依赖项包括在内
- 在
src/main/resources
文件夹中创建一个logback.xml
- 完成的
1.构建工具
1.1 对于 Maven
pom.xml
<properties><jdk.version>1.7</jdk.version><spring.version>4.1.6.RELEASE</spring.version><logback.version>1.1.3</logback.version><jcl.slf4j.version>1.7.12</jcl.slf4j.version></properties><dependencies><!-- 1\. exclude commons-logging --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version><exclusions><exclusion><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!- 2\. Bridge logging from JCL to SLF4j--><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>${jcl.slf4j.version}</version></dependency><!-- 3\. logback --><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>${logback.version}</version></dependency><dependencies>
1.2 度
build.gradle
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'eclipse-wtp'repositories {mavenCentral()
}//1\. exclude commons-logging
configurations.all {exclude group: "commons-logging", module: "commons-logging"
}dependencies {//2\. bridge logging from JCL to SLF4jcompile 'org.slf4j:jcl-over-slf4j:1.7.12'//3\. Logbackcompile 'ch.qos.logback:logback-classic:1.1.3'compile 'org.springframework:spring-webmvc:4.1.6.RELEASE'
}
2.项目目录
在src/main/resources
文件夹中创建一个logback.xml
3.logback.xml
此logback.xml
将所有日志发送到控制台。
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration><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" level="debug" additivity="false"><appender-ref ref="STDOUT" /></logger><logger name="com.mkyong.helloworld" level="debug" additivity="false"><appender-ref ref="STDOUT" /></logger><root level="error"><appender-ref ref="STDOUT" /></root></configuration>
对于其他附加器(日志输出),比如日志到文件,请访问这个 log.xml 示例,或者这个日志回溯附加器指南
4.回溯示例
WelcomeController.java
package com.mkyong.common.controller;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;@Controller
public class WelcomeController {private static final Logger logger = LoggerFactory.getLogger(WelcomeController.class);@RequestMapping(value = "/", method = RequestMethod.GET)public String welcome(Model model) {logger.debug("welcome() is executed, value {}", "mkyong");logger.error("This is Error message", new Exception("Testing"));model.addAttribute("msg", "Hello Spring MVC + Logback");return "welcome";}}
5.演示
下载源代码,用 Maven 或者 Gradle 运行。
5.1 Maven
mvn jetty:run
5.2 Gradle
gradle jettyRun
访问网址:http://localhost:8080/spring-MVC-log back
Console
...
2015-06-19 21:53:33 DEBUG o.s.web.servlet.DispatcherServlet - Initializing servlet 'hello-dispatcher'
2015-06-19 21:53:33 DEBUG o.s.w.c.s.StandardServletEnvironment - Adding [servletConfigInitParams] PropertySource with lowest search precedence
2015-06-19 21:53:33 DEBUG o.s.w.c.s.StandardServletEnvironment - Adding [servletContextInitParams] PropertySource with lowest search precedence
2015-06-19 21:53:33 DEBUG o.s.w.c.s.StandardServletEnvironment - Adding [jndiProperties] PropertySource with lowest search precedence
2015-06-19 21:53:33 DEBUG o.s.w.c.s.StandardServletEnvironment - Adding [systemProperties] PropertySource with lowest search precedence
2015-06-19 21:53:33 DEBUG o.s.w.c.s.StandardServletEnvironment - Adding [systemEnvironment] PropertySource with lowest search precedence
2015-06-19 21:53:33 DEBUG o.s.w.c.s.StandardServletEnvironment - Initialized StandardServletEnvironment with PropertySources [servletConfigInitParams,servletContextInitParams,jndiProperties,systemProperties,systemEnvironment]
Jun 19, 2015 9:53:33 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'hello-dispatcher'
20
...
2015-06-19 21:53:45 DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'welcomeController'
2015-06-19 21:53:45 DEBUG o.s.web.servlet.DispatcherServlet - Last-Modified value for [/spring-mvc-logback/] is: -1
2015-06-19 21:53:45 ERROR c.m.c.controller.WelcomeController - This is Error message
java.lang.Exception: Testingat com.mkyong.common.controller.WelcomeController.welcome(WelcomeController.java:21) [WelcomeController.class:na]at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_65]at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.7.0_65]at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.7.0_65]at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.7.0_65]
...
Spring 和 web 应用程序日志都将被发送到控制台。
下载源代码
Download it – spring-mvc-logback-example.zip (6 KB)
参考
- 春季官方指南——伐木
- Logback 官网
- logback.xml 示例
- Spring MVC + Log4j
Spring MVC MultiActionController 注释示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-multiactioncontroller-annotation-example/
在本教程中,我们将向您展示如何使用@RequestMapping
开发一个基于 Spring MVC 注释的 MultiActionController 。
在基于 XML 的 MultiActionController 中,您必须配置方法名解析器(InternalPathMethodNameResolver、propertiesmethodname resolver或parametermethodname resolver)来将 URL 映射到特定的方法名。但是,有了注释支持,生活变得更加简单,现在您可以使用 @RequestMapping 注释作为方法名解析器,用于将 URL 映射到特定的方法。
Note
This annotation-based example is converted from the last Spring MVC MultiActionController XML-based example. So, please compare and spots the different.
要配置它,在方法名上方定义映射 URL 的 @RequestMapping 。
package com.mkyong.common.controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;@Controller
public class CustomerController{@RequestMapping("/customer/add.htm")public ModelAndView add(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerAddView");}@RequestMapping("/customer/delete.htm")public ModelAndView delete(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerDeleteView");}@RequestMapping("/customer/update.htm")public ModelAndView update(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerUpdateView");}@RequestMapping("/customer/list.htm")public ModelAndView list(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerListView");}
}
现在,URL 将按照以下模式映射到方法名:
- /customer/add . htm –> add()方法
- /customer/delete . htm –> delete()方法
- /customer/update . htm –> update()方法
- /customer/list . htm –> list()方法
Note
In Spring MVC, this @RequestMapping
is always the most flexible and easy to use mapping mechanism.
下载源代码
Download it – SpringMVC-MultiActionController-Annotation-Example.zip (7KB)spring mvc (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/20190214221647/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
Spring MVC 多动作控制器示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-multiactioncontroller-example/
在 Spring MVC 应用程序中, MultiActionController 用于将相关的动作分组到一个控制器中,方法处理程序必须遵循以下签名:
public (ModelAndView | Map | String | void) actionName(HttpServletRequest, HttpServletResponse [,HttpSession] [,CommandObject]);
1.多动作控制器
请参见 MultiActionController 示例。
package com.mkyong.common.controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;public class CustomerController extends MultiActionController{public ModelAndView add(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerPage", "msg","add() method");}public ModelAndView delete(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerPage", "msg","delete() method");}public ModelAndView update(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerPage", "msg","update() method");}public ModelAndView list(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerPage", "msg","list() method");}}
配置了控制器 class name handler 映射。
<beans ...><bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.common.controller.CustomerController" /></beans>
2.映射示例
现在,重新请求的 URL 将按照以下模式映射到方法名:
- 客户控制人—>/客户/*
- /customer/ 添加。htm->添加()
- /customer/ 删除。htm->删除()
- /customer/ 更新。htm->更新()
- /客户/ 列表。htm->列表()
3.InternalPathMethodNameResolver
InternalPathMethodNameResolver 是默认的 MultiActionController 实现,用于将 URL 映射到方法名。但是,您仍然可以给方法名添加前缀或后缀:
<beans ...><bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.common.controller.CustomerController"><property name="methodNameResolver"><bean class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver"><property name="prefix" value="test" /><property name="suffix" value="Customer" /></bean></property></bean>
</beans>
现在,URL 将按照以下模式映射到方法名:
- 客户控制人—>/客户/*
- /customer/ 添加。htm->测试添加客户()
- /customer/ 删除。htm->测试删除客户()
- /customer/ 更新。htm—>测试更新客户()
- /客户/ 列表。htm—>测试列表 C 客户()
Note
With annotation, the MultiActionController is more easy to configure, visit this MultiActionController annotation example for detail.
下载源代码
Download it – SpringMVC-MultiActionController-Example.zip (7KB)
参考
- 多动作控制器 Javadoc
- InternalPathMethodNameResolver Javadoc
spring mvc
spring MVC–bean 名称“xxx”的 BindingResult 和 plain target 对象都不能用作请求属性。
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-neither-bindingresult-nor-plain-target-object-for-bean-name-xxx-available-as-request-attribute/
问题
最近刚刚将 Spring MVC 基于 xml 的表单控制器转换为基于注释的表单控制器,出现如下错误信息。
严重:bean 名称“customerForm”的 BindingResult 和 plain target 对象都不能用作请求属性
Java . lang . illegalstateexception:bean 名称“customerForm”的 BindingResult 和 plain target 对象都不能用作请求属性
上述错误消息清楚地表明“customer form”bean 不存在,并且我 100%确定视图解析器配置正确,并且“CustomerForm.jsp”视图页面存在。
表单控制器
@Controller
@RequestMapping("/customer.htm")
public class CustomerController{@RequestMapping(method = RequestMethod.GET)public String initForm(ModelMap model){//return form viewreturn "CustomerForm";}
查看解析器
...<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>
解决办法
造成这种情况的根本原因是 JSP 页面中的视图名称不正确,见下文。
<form:form method="POST" commandName="customerForm">
“customerForm”不再存在于控制器映射中,请参见注释映射@ request mapping("/customer . htm "),它应该更改为“customer”。
<form:form method="POST" commandName="customer">
类似案例
我在 validator 或 SimpleFormController 类中也见过很多类似的情况。要解决它,只需确保映射名称匹配或存在。
spring mvc
spring MVC ParameterizableViewController 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-parameterizableviewcontroller-example/
一般来说,要在 Spring MVC 应用中返回一个视图或页面,需要创建一个类,该类扩展了 AbstractController ,并返回一个 ModelAndView() 对象。
public class WelcomeController extends AbstractController{@Overrideprotected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse response) throws Exception {ModelAndView model = new ModelAndView("WelcomePage");return model;}}
在 bean 配置文件中,声明了一个ControllerClassNameHandlerMapping来自动检测映射。
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.common.controller.WelcomeController" />
但是,您不认为对于一个简单的重定向任务来说,这种配置太多了吗?幸运的是,Spring 自带了ParameterizableViewController来简化上述过程。使用ParameterizableViewController,您不再需要在控制器类中硬编码视图名称,而是通过 ParameterizableViewController 的“ viewName 属性声明视图名称。
Note
The ParameterizableViewController is a subclass of AbstractController, and return a ModelAndView based on the “viewName” property, it’s purely a redirect class, nothing more, nothing less 😃
ParameterizableViewController.java
public class ParameterizableViewController extends AbstractController{
//...
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)throws Exception {return new ModelAndView(getViewName());
}
辅导的
在本教程中,它展示了使用ParameterizableViewController控制器在 Spring MVC 应用程序中进行页面重定向。
1.ParameterizableViewController
不需要控制器类,只需声明ParameterizableViewControllerbean,并通过“ viewName 属性指定视图名称。此外,您必须为它定义一个显式映射。
<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 class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="mappings"><props><prop key="/welcome.htm">welcomeController</prop></props></property></bean><bean name="welcomeController" class="org.springframework.web.servlet.mvc.ParameterizableViewController"><property name="viewName" value="WelcomePage" /></bean><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></beans>
Define an explicit mapping is required.
<beans ...>
//...
<bean
class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean name="welcomeController" class="org.springframework.web.servlet.mvc.ParameterizableViewController"><property name="viewName" value="WelcomePage" />
</bean>
//...
</beans>
在上面代码片段中,您是否期望一个名为“welcome”的视图会返回一个“WelcomePage”?抱歉,不是,你得定义一个显式映射,因为ControllerClassNameHandlerMapping不会为任何内置的 Spring MVC 控制器生成映射。
2.视角
只是一个简单的 JSP 来显示标题行。
WelcomePage.jsp.jsp
<html>
<body>
<h2>ParameterizableViewController Example</h2>
</body>
</html>
3.演示
通过“http://localhost:8080/spring MVC/welcome . htm”访问,“【welcome.htm】T3”会返回一个“/we b-INF/pages/welcompage . JSP”。
下载源代码
Download it – SpringMVC-ParameterizableViewController-Example.zip (7KB)
参考
- ParameterizableViewController 文档
- Spring MVC SimpleUrlHandlerMapping 示例
spring mvc
Spring MVC 参数 MethodNameResolver 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-parametermethodnameresolver-example/
parametermethodname resolver,MultiActionController 方法名解析器通过请求参数名将 URL 映射到方法名,参数名可通过“ paramName 属性定制。请参见以下示例:
1.多动作控制器
一个 MultiActionController 示例。
package com.mkyong.common.controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;public class CustomerController extends MultiActionController{public ModelAndView add(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerPage", "msg","add() method");}public ModelAndView delete(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerPage", "msg","delete() method");}public ModelAndView update(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerPage", "msg","update() method");}public ModelAndView list(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerPage", "msg","list() method");}}
2.ParameterMethodNameResolver
配置了参数方法名称解析器,通过“参数名称属性定义参数名称:
<beans ...><bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.common.controller.CustomerController"><property name="methodNameResolver"><bean class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"><property name="paramName" value="action"/></bean></property></bean></beans>
现在,URL 将通过“action”请求参数名称映射到方法名称:
- /customer/*。htm ?action = add–>add()方法
- /customer/whatever.htm ?action = add–>add()方法
- /customer/*。htm ?action = update–>update()方法
- /customer/*。htm ?action = delete–>delete()方法
- /customer/*。htm ?action = list–>list()方法
附注“ ***** ”指任何文本。
Note
By default, MultiActionController is used the InternalPathMethodNameResolver to map URL to the corresponds method name. ## 下载源代码
Download it – SpringMVC-ParameterMethodNameResolver-Example.zip (7KB)
参考
- 参数 MethodNameResolver Javadoc
- Spring MVC multi action controller 示例
spring mvc
Spring MVC 密码示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-password-example/
在 Spring MVC 中,可以使用 < form:password / > 标签来呈现一个 HTML 密码字段。举个例子,
<form:password path="password" />
它将呈现以下 HTML 代码
<input id="password" name="password" type="password" value=""/>
Note
In Spring’s documentation, it mention about the ‘showPassword‘ attribute will display the password value, but it’s failed in my testing, may be you can try it yourself.
在本教程中,我们将向您展示如何使用 Spring 的表单标签“ password ”来呈现两个 HTML 密码字段——“password”和“confirmPassword”。此外,添加一个验证器检查两个密码字段:不得为空,并且“密码”字段必须与“确认密码”字段匹配。
1.控制器
一个 SimpleFormController 来处理表单值。
文件:PasswordController.java
package com.mkyong.customer.controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import com.mkyong.customer.model.Customer;public class PasswordController extends SimpleFormController{public PasswordController(){setCommandClass(Customer.class);setCommandName("customerForm");}@Overrideprotected ModelAndView onSubmit(HttpServletRequest request,HttpServletResponse response, Object command, BindException errors)throws Exception {Customer customer = (Customer)command;return new ModelAndView("CustomerSuccess","customer",customer);}}
2.模型
存储密码值的客户对象。
文件:Customer.java
package com.mkyong.customer.model;public class Customer{String password;String confirmPassword;//getter and setter methods for password and confirmPassword
}
3.表单验证器
创建一个密码验证器类来检查两个密码字段:不得为空,“密码”和“确认密码”必须匹配。否则,从资源包(属性文件)中获取相应的消息。
文件:PasswordValidator.java
package com.mkyong.customer.validator;import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;import com.mkyong.customer.model.Customer;public class PasswordValidator implements Validator{@Overridepublic boolean supports(Class clazz) {//just validate the Customer instancesreturn Customer.class.isAssignableFrom(clazz);}@Overridepublic void validate(Object target, Errors errors) {ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password","required.password", "Field name is required.");ValidationUtils.rejectIfEmptyOrWhitespace(errors, "confirmPassword","required.confirmPassword", "Field name is required.");Customer cust = (Customer)target;if(!(cust.getPassword().equals(cust.getConfirmPassword()))){errors.rejectValue("password", "notmatch.password");}}}
文件:message.properties
required.password = Password is required!
required.passwordConfirm = Confirm password is required!
notmatch.password = Password and Conform password is not match!
4.视角
一个 JSP 页面使用 Spring 的表单标签" password "来呈现两个 HTML 密码字段,并放置一些 CSS 样式来突出显示错误消息。
文件:CustomerForm.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>Spring's form password example</h2><form:form method="POST" commandName="customerForm"><form:errors path="*" cssClass="errorblock" element="div" /><table><tr><td>Password :</td><td><form:password path="password" /></td><td><form:errors path="password" cssClass="error" /></td></tr><tr><td>Confirm Password :</td><td><form:password path="confirmPassword" /></td><td><form:errors path="confirmPassword" cssClass="error" /></td></tr><tr><td colspan="3"><input type="submit" /></td></tr></table></form:form></body>
</html>
如果表单已提交,则呈现成功页面并显示提交的密码值。
文件:CustomerSuccess.jsp
<html>
<body><h2>Spring's form password example</h2>Password : ${customer.password}<br /> Confirm Password : ${customer.confirmPassword}</body>
</html>
5.弹簧豆配置
全部链接起来~
<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"><beanclass="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.customer.controller.PasswordController"><property name="formView" value="CustomerForm" /><property name="successView" value="CustomerSuccess" /><!-- Map a validator --><property name="validator"><bean class="com.mkyong.customer.validator.PasswordValidator" /></property></bean><!-- Register the Customer.properties --><bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basename" value="message" /></bean><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></beans>
6.演示
访问页面-http://localhost:8080/SpringMVCForm/password . htm
如果提交表单时“密码”与“确认密码”不匹配,则显示并突出显示错误消息。
如果表单提交成功,只需显示提交的密码值。
下载源代码
Download it – SpringMVCForm-Password-Example.zip (9KB)password spring mvc
spring MVC properties methodnameresolver 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-propertiesmethodnameresolver-example/
properties methodnameresolver,一个灵活的 MultiActionController 方法名解析器,用来明确定义 URL 和方法名之间的映射。请参见以下示例:
1.多动作控制器
一个 MultiActionController 示例。
package com.mkyong.common.controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;public class CustomerController extends MultiActionController{public ModelAndView add(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerPage", "msg","add() method");}public ModelAndView delete(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerPage", "msg","delete() method");}public ModelAndView update(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerPage", "msg","update() method");}public ModelAndView list(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("CustomerPage", "msg","list() method");}}
2.PropertiesMethodNameResolver
使用propertiesmethodname resolver,您可以轻松地将任何 URL 名称映射到对应的方法名称:
<beans ...><bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.common.controller.CustomerController"><property name="methodNameResolver"><bean class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"><property name="mappings"><props><prop key="/customer/a.htm">add</prop><prop key="/customer/b.htm">update</prop><prop key="/customer/c.htm">delete</prop><prop key="/customer/d.htm">list</prop><prop key="/customer/whatever.htm">add</prop></props></property></bean></property></bean></beans>
现在,URL 将按照以下模式映射到方法名:
- /customer/a . htm –> add()方法
- /customer/b . htm –> update()方法
- /customer/c . htm –> delete()方法
- /customer/d . htm –> list()方法
- /customer/whatever . htm –> add()方法
Note
By default, MultiActionController is used the InternalPathMethodNameResolver to map URL to the corresponds method name. ## 下载源代码
Download it – SpringMVC-PropertiesMethodNameResolver-Example.zip (7KB)
参考
- 属性 MethodNameResolver Javadoc
- Spring MVC multi action controller 示例
spring mvc
Spring MVC 单选按钮和单选按钮示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-radiobutton-and-radiobuttons-example/
在 Spring MVC 中, <表单:radiobutton / > 用于渲染一个 HTML 单选按钮,单选按钮值硬编码在 JSP 页面内部;而 <表单:radiobuttons / > 用于呈现多个单选按钮,单选按钮值在运行时生成。
在本教程中,我们将向您展示如何使用 <表单:radiobutton / > 和 <表单:radio button/>。
1.
生成一个单选按钮,并硬编码该值。
public class Customer{String sex;//...
}
<form:radiobutton path="sex" value="M"/>Male
<form:radiobutton path="sex" value="F"/>Female
Default value…
To make the “Male” as the default selected value in above radio buttons, just set the “sex” property to “M“, for example :
public class Customer{String sex = "M";//...
}
或者
//SimpleFormController...
@Override
protected Object formBackingObject(HttpServletRequest request)throws Exception {Customer cust = new Customer();//Make "Male" as the default radio button selected valuecust.setSex("M");return cust;}
2.
生成多个单选按钮,这些值在运行时生成。
//SimpleFormController...
protected Map referenceData(HttpServletRequest request) throws Exception {Map referenceData = new HashMap();List<String> numberList = new ArrayList<String>();numberList.add("Number 1");numberList.add("Number 2");numberList.add("Number 3");numberList.add("Number 4");numberList.add("Number 5");referenceData.put("numberList", numberList);return referenceData;
}
<form:radiobuttons path="favNumber" items="${numberList}" />
Default value…
To make the “Number 1” as the default selected value in above radio buttons, just set the “favNumber” property to “Number 1“, for example :
public class Customer{String favNumber = "Number 1";//...
}
或者
//SimpleFormController...
@Override
protected Object formBackingObject(HttpServletRequest request)throws Exception {Customer cust = new Customer();//Make "Number 1" as the default radio button selected valuecust.setFavNumber("Number 1")return cust;
}
Note
For radio button selection, as long as the “path” or “property” is equal to the “radio button value“, the radio button will be selected automatically. ## 完整的单选按钮示例
让我们来看一个完整的 Spring MVC 单选按钮示例:
1.模型
存储单选按钮值的客户模型类。
文件:Customer.java
package com.mkyong.customer.model;public class Customer{String favNumber;String sex;public String getFavNumber() {return favNumber;}public void setFavNumber(String favNumber) {this.favNumber = favNumber;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}}
2.控制器
一个SimpleFormController
来处理表单单选按钮的值。将单选按钮“M”设为默认选定值。
文件:RadioButtonController.java
package com.mkyong.customer.controller;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import com.mkyong.customer.model.Customer;public class RadioButtonController extends SimpleFormController{public RadioButtonController(){setCommandClass(Customer.class);setCommandName("customerForm");}@Overrideprotected Object formBackingObject(HttpServletRequest request)throws Exception {Customer cust = new Customer();//Make "Make" as default radio button checked valuecust.setSex("M");return cust;}@Overrideprotected ModelAndView onSubmit(HttpServletRequest request,HttpServletResponse response, Object command, BindException errors)throws Exception {Customer customer = (Customer)command;return new ModelAndView("CustomerSuccess","customer",customer);}protected Map referenceData(HttpServletRequest request) throws Exception {Map referenceData = new HashMap();List<String> numberList = new ArrayList<String>();numberList.add("Number 1");numberList.add("Number 2");numberList.add("Number 3");numberList.add("Number 4");numberList.add("Number 5");referenceData.put("numberList", numberList);return referenceData;}
}
3.验证器
一个简单的表单验证器,确保“性别”和“号码”单选按钮被选中。
文件:RadioButtonValidator.java
package com.mkyong.customer.validator;import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;import com.mkyong.customer.model.Customer;public class RadioButtonValidator implements Validator{@Overridepublic boolean supports(Class clazz) {//just validate the Customer instancesreturn Customer.class.isAssignableFrom(clazz);}@Overridepublic void validate(Object target, Errors errors) {Customer cust = (Customer)target;ValidationUtils.rejectIfEmptyOrWhitespace(errors, "sex", "required.sex");ValidationUtils.rejectIfEmptyOrWhitespace(errors, "favNumber", "required.favNumber");}
}
文件:message.properties
required.sex = Please select a sex!
required.favNumber = Please select a number!
4.视角
一个 JSP 页面展示了 Spring 的表单标签<form:radio button/>和<form:radio button/>的使用。
文件:CustomerForm.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>Spring's form radio button example</h2><form:form method="POST" commandName="customerForm"><form:errors path="*" cssClass="errorblock" element="div" /><table><tr><td>Sex :</td><td><form:radiobutton path="sex" value="M" />Male <form:radiobuttonpath="sex" value="F" />Female</td><td><form:errors path="sex" cssClass="error" /></td></tr><tr><td>Choose a number :</td><td><form:radiobuttons path="favNumber" items="${numberList}" /></td><td><form:errors path="favNumber" cssClass="error" /></td></tr><tr><td colspan="3"><input type="submit" /></td></tr></table></form:form></body>
</html>
使用 JSTL 循环遍历提交的单选按钮值,并显示它。
文件:CustomerSuccess.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><html>
<body><h2>Spring's form radio button example</h2>Sex : ${customer.sex}<br /> Favourite Number : ${customer.favNumber}<br />
</body>
</html>
5.弹簧豆配置
全部链接起来~
<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"><beanclass="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.customer.controller.RadioButtonController"><property name="formView" value="CustomerForm" /><property name="successView" value="CustomerSuccess" /><!-- Map a validator --><property name="validator"><bean class="com.mkyong.customer.validator.RadioButtonValidator" /></property></bean><!-- Register the Customer.properties --><bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basename" value="message" /></bean><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>
</beans>
6.演示
访问页面-http://localhost:8080/SpringMVCForm/radio button . htm
如果用户在提交表单时没有选择任何单选按钮值,则显示并突出显示错误消息。
如果表单提交成功,只需显示已提交的单选按钮值。
下载源代码
Download it – SpringMVCForm-RadioButton-Example.zip (9KB)radio button spring mvc
Spring MVC 重定向视图示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-redirectview-example/
在 Spring MVC 中,org . Spring framework . web . servlet . view . redirect view,顾名思义,视图重定向到另一个绝对的、上下文相对的或当前请求相对的 URL。在本教程中,我们向您展示了一个使用 RedirectView 类的完整示例。
1.重定向视图
声明一个 RedirectView bean,命名为“ DummyRedirect ”,重定向到 URL“【DummyRedirectPage.htm】T2”。
文件:spring-views.xml
<beans ...><!-- Redirect view --> <bean id="DummyRedirect" class="org.springframework.web.servlet.view.RedirectView"><property name="url" value="DummyRedirectPage.htm" /></bean>
</beans>
2.控制器
一个返回名为" DummyRedirect "的 ModelAndView 的控制器,它是一个 RedirectView 视图。
文件:DummyController.java
package com.mkyong.common.controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;public class DummyController extends AbstractController{@Overrideprotected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("DummyRedirect");}
}
3.弹簧配置
声明了所有映射。
文件:mvc-dispatcher-servlet.xml
<beans ...><bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.common.controller.DummyController" /><bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="mappings"><props><prop key="/DummyRedirectPage.htm">dummyRedirectController</prop></props></property></bean><bean id="dummyRedirectController" class="org.springframework.web.servlet.mvc.ParameterizableViewController"><property name="viewName" value="DummyPage" /></bean><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><property name="order" value="1" /></bean><bean class="org.springframework.web.servlet.view.XmlViewResolver"><property name="location"><value>/WEB-INF/spring-views.xml</value></property><property name="order" value="0" /></bean></beans>
4.它是如何工作的?
1.访问网址http://localhost:8080/spring MVC/dummy . htm。
2." ControllerClassNameHandlerMapping " matched "dummy controller"并返回一个modeland view(" DummyRedirect ")。
3." XmlViewResolver "匹配后返回一个 URL "【DummyRedirectPage.htm】T2"。
<bean id="DummyRedirect" class="org.springframework.web.servlet.view.RedirectView"><property name="url" value="DummyRedirectPage.htm" /></bean>
4." SimpleUrlHandlerMapping "匹配后返回一个控制器" dummyRedirectController "。
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="mappings"><props><prop key="/DummyRedirectPage.htm">dummyRedirectController</prop></props></property></bean>
5.ParameterizableViewController 控制器“ dummyRedirectController ”返回一个名为“ DummyPage 的视图。
<bean id="dummyRedirectController" class="org.springframework.web.servlet.mvc.ParameterizableViewController"><property name="viewName" value="DummyPage" /></bean>
6.InternalResourceViewResolver 对其进行匹配并返回最终的 jsp 页面,"/we b-INF/pages/dummy page . JSP"。
<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><property name="order" value="1" /></bean>
7. URL changed to “ http://localhost:8080/SpringMVC/DummyRedirectPage.htm “.
Redirect Prefix
Alternative, if you have InternalResourceViewResolver configured, you can use the “Redirect Prefix” in the view name to resolve the redirect view. For example,
文件:DummyController.java
//...
public class DummyController extends AbstractController{@Overrideprotected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse response) throws Exception {return new ModelAndView("redirect:DummyRedirectPage.htm");}
}
Use case
One of the use case is applying the “RedirectView” concept to solve the duplicated form submission in Spring MVC.
下载源代码
Download it – SpringMVC-RedirectView-Example.zip (7KB)
参考
- 重定向查看 Javadoc
- SpringSource 重定向视图解释
- 到底如何使用重定向视图?
spring mvc
spring MVC ResourceBundleViewResolver 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-resourcebundleviewresolver-example/
在 Spring MVC 中,ResourceBundleViewResolver用于解析“基于视图 beans 中名为”的视图。属性”文件。
默认情况下,ResourceBundleViewResolver
将从文件 views.properties 中加载视图 beans,该文件位于项目类路径的根目录下。但是,这个位置可以通过“ basename 属性覆盖,例如,
<beans ...><bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"><property name="basename" value="spring-views" /></bean>
</beans>
在上面的例子中,它从" spring-views.properties "加载视图 beans,它位于项目类路径的根。
Note
The ResourceBundleViewResolver
has the ability to load view beans from different resource bundles for different locales, but this use case is rarely required.
ResourceBundleViewResolver 示例向您展示了它的工作原理:
1.控制器
一个控制器类,返回一个视图,名为“ WelcomePage ”。
//...
public class WelcomeController extends AbstractController{@Overrideprotected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse response) throws Exception {ModelAndView model = new ModelAndView("WelcomePage");return model;}
}
2.ResourceBundleViewResolver
在 Spring 的 bean 配置文件中注册ResourceBundleViewResolver
,将默认的视图 bean 位置更改为“ spring-views.properties ”。
<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 class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><!-- Register the bean --><bean class="com.mkyong.common.controller.WelcomeController" /><bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"><property name="basename" value="spring-views" /></bean></beans>
3.查看 beans
将每个视图 bean 声明为普通的资源包样式(键和消息),其中
- " WelcomePage "是要匹配的视图名称。
- 。(类)是视图的类型。
- 。url 是视图的 url 位置。
文件:spring-views.properties
WelcomePage.(class)=org.springframework.web.servlet.view.JstlView
WelcomePage.url=/WEB-INF/pages/WelcomePage.jsp
Note
Put this “spring-views.properties
” file on your project class path.How it works ?
When view name “WelcomPage” is returned by controller, the ResourceBundleViewResolver will find the key start with “WelcomPage” in “spring-views.properties” file, and return the corresponds view’s URL “/WEB-INF/pages/WelcomPage.jsp” back to the DispatcherServlet.
下载源代码
Download it – SpringMVC-ResourceBundleViewResolver-Example.zip (7 KB)
参考
- ResourceBundleViewResolver 文档
spring mvc
spring MVC SimpleUrlHandlerMapping 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-simpleurlhandlermapping-example/
在 Spring MVC 应用中, SimpleUrlHandlerMapping 是最灵活的处理程序映射类,它允许开发者显式地指定 URL 模式和处理程序的映射。
简单 URL handler 映射可以用两种方式声明。
1.方法 1–道具钥匙
属性键是 URL 模式,而属性值是处理程序 id 或名称。
<beans ...><bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="mappings"><props><prop key="/welcome.htm">welcomeController</prop><prop key="/*/welcome.htm">welcomeController</prop><prop key="/helloGuest.htm">helloGuestController</prop></props></property></bean><bean id="welcomeController" class="com.mkyong.common.controller.WelcomeController" /><bean id="helloGuestController" class="com.mkyong.common.controller.HelloGuestController" /></beans>
2.方法 1–价值
左侧是 URL 模式,右侧是处理程序 id 或名称,用等号“=”隔开。
<beans ...><bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="mappings"><value>/welcome.htm=welcomeController/*/welcome.htm=welcomeController/helloGuest.htm=helloGuestController</value></property></bean><bean id="welcomeController" class="com.mkyong.common.controller.WelcomeController" /><bean id="helloGuestController" class="com.mkyong.common.controller.HelloGuestController" /></beans>
3.演示
两者都定义了相同的处理程序映射。
- /welcome . htm –> welcome controller。
- /{ any }/welcome . htm –> welcome controller。
- /hello guest . htm –> hello guest controller。
下载源代码
Download it – SpringMVC-SimpleUrlHandlerMapping-Example.zip (7KB)
参考
- SimpleUrlHandlerMapping javadoc
spring mvc url mapping
Spring MVC textarea 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-textarea-example/
在 Spring MVC 中,使用 < form:textarea / > 渲染一个 HTML textarea 字段。举个例子,
<form:textarea path="address" rows="5" cols="30" />
它将呈现以下 HTML 代码
<textarea id="address" name="address" rows="5" cols="30"></textarea>
在本教程中,我们将向您展示如何使用 Spring 的表单标签“ textarea ”来呈现一个 HTML textarea 来存储“地址”。此外,添加一个验证器来确保提交表单时 texarea 不为空。
1.控制器
一个 SimpleFormController 来处理表单值。
文件:TextAreaController.java
package com.mkyong.customer.controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import com.mkyong.customer.model.Customer;public class TextAreaController extends SimpleFormController{public TextAreaController(){setCommandClass(Customer.class);setCommandName("customerForm");}@Overrideprotected ModelAndView onSubmit(HttpServletRequest request,HttpServletResponse response, Object command, BindException errors)throws Exception {Customer customer = (Customer)command;return new ModelAndView("CustomerSuccess","customer",customer);}}
2.模型
存储 textarea 值的客户对象。
文件:Customer.java
package com.mkyong.customer.model;public class Customer{String address;//getter and setter methods for address
}
3.表单验证器
创建一个表单验证器类,并使用 ValidationUtils 类来确保“地址”不为空,否则,从相应的资源包(属性文件)中获取“ required.address 消息。
文件:CustomerValidator.java
package com.mkyong.customer.validator;import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;import com.mkyong.customer.model.Customer;public class CustomerValidator implements Validator{@Overridepublic boolean supports(Class clazz) {//just validate the Customer instancesreturn Customer.class.isAssignableFrom(clazz);}@Overridepublic void validate(Object target, Errors errors) {ValidationUtils.rejectIfEmptyOrWhitespace(errors, "address","required.address", "Field name is required.");}
}
文件:message.properties
required.address = Address is required!
4.视角
一个 JSP 页面使用 Spring 的表单标签" textarea "来呈现一个 HTML textarea,并放置一些 CSS 样式来突出显示错误消息。
文件:CustomerForm.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>Spring's form textarea example</h2><form:form method="POST" commandName="customerForm"><form:errors path="*" cssClass="errorblock" element="div" /><table><tr><td>Address :</td><td><form:textarea path="address" rows="5" cols="30" /></td><td><form:errors path="address" cssClass="error" /></td></tr><tr><td colspan="3"><input type="submit" /></td></tr></table></form:form></body>
</html>
如果表单已提交,则呈现成功的页面并显示提交的 textarea 值。
文件:CustomerSuccess.jsp
<html>
<body><h2>Spring's form textarea example</h2>Address : ${customer.address}</body>
</html>
5.弹簧豆配置
全部链接起来~
<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"><beanclass="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.customer.controller.TextAreaController"><property name="formView" value="CustomerForm" /><property name="successView" value="CustomerSuccess" /><!-- Map a validator --><property name="validator"><bean class="com.mkyong.customer.validator.CustomerValidator" /></property></bean><!-- Register the Customer.properties --><bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basename" value="message" /></bean><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></beans>
6.演示
访问页面-http://localhost:8080/SpringMVCForm/textarea . htm
如果提交表单时 textarea 值为空,则显示并突出显示错误消息。
如果表单提交成功,只需显示提交的 textarea 值。
下载源代码
Download it – SpringMVCForm-TextArea-Example.zip (9KB)spring mvc textarea
Spring MVC 文本框示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-textbox-example/
在 Spring MVC 中,可以使用 < form:input / > 标签来呈现一个 HTML textbox 字段。举个例子,
<form:input path="userName" />
它将呈现以下 HTML 代码
<input id="userName" name="userName" type="text" value=""/>
在本教程中,我们将向您展示如何使用 Spring 的表单标签" input "来呈现一个 HTML textbox 来存储"用户名"。此外,添加一个空检查验证器来确保 textbox 值不为空。
1.控制器
一个 SimpleFormController 来处理表单值,并将表单值链接到客户对象。
文件:TextBoxController.java
package com.mkyong.customer.controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import com.mkyong.customer.model.Customer;public class TextBoxController extends SimpleFormController{public TextBoxController(){setCommandClass(Customer.class);setCommandName("customerForm");}@Overrideprotected ModelAndView onSubmit(HttpServletRequest request,HttpServletResponse response, Object command, BindException errors)throws Exception {Customer customer = (Customer)command;return new ModelAndView("CustomerSuccess","customer",customer);}
}
2.模型
存储文本框值的客户对象。
文件:Customer.java
package com.mkyong.customer.model;public class Customer{String userName;//getter and setter methods
}
3.表单验证器
创建一个表单验证器类,并使用 ValidationUtils 类来确保“用户名”不为空,否则,从相应的资源包(属性文件)中获取“ required.userName 消息。
文件:CustomerValidator.java
package com.mkyong.customer.validator;import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import com.mkyong.customer.model.Customer;public class CustomerValidator implements Validator{@Overridepublic boolean supports(Class clazz) {//just validate the Customer instancesreturn Customer.class.isAssignableFrom(clazz);}@Overridepublic void validate(Object target, Errors errors) {ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName","required.userName", "Field name is required.");}}
文件:message.properties
required.userName = username is required!
4.视角
一个 JSP 页面使用 Spring 的表单标签" input "来呈现一个 HTML textbox,并放置一些 CSS 样式来突出显示错误消息。
文件:CustomerForm.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>Spring's form textbox example</h2><form:form method="POST" commandName="customerForm"><form:errors path="*" cssClass="errorblock" element="div" /><table><tr><td>Username :</td><td><form:input path="userName" /></td><td><form:errors path="userName" cssClass="error" /></td></tr><tr><td colspan="3"><input type="submit" /></td></tr></table></form:form></body>
</html>
如果表单已提交,则呈现成功的页面并显示已提交的文本框值。
文件:CustomerSuccess.jsp
<html>
<body><h2>Spring's form textbox example</h2>userName : ${customer.userName}</body>
</html>
5.弹簧豆配置
全部链接起来~
<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"><beanclass="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><bean class="com.mkyong.customer.controller.TextBoxController"><property name="formView" value="CustomerForm" /><property name="successView" value="CustomerSuccess" /><!-- Map a validator --><property name="validator"><bean class="com.mkyong.customer.validator.CustomerValidator" /></property></bean><!-- Register the Customer.properties --><bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"><property name="basename" value="message" /></bean><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></beans>
6.演示
访问页面-http://localhost:8080/SpringMVCForm/textbox . htm
如果提交表单时文本框值为空,则显示并突出显示错误消息。
如果表单提交成功,只显示提交的文本框值。
下载源代码
Download it – SpringMVCForm-TextBox-Example.zip (9KB)spring mvc textbox
Spring MVC 教程
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/tutorials/spring-mvc-tutorials/
Spring MVC ,一个 Java 模型-视图-控制器(MVC) web 框架,它建立在 Spring 反转控制(IoC)框架之上。
Rewrite and Spring 4 (12/Jun/2015)
I’m rewriting the outdated articles and upgrade it to Spring 4, give me some time 🙂
1.Spring MVC Hello World
快速启动 Spring MVC 框架的一些 hello world 示例。
- Gradle–Spring 4 MVC Hello World 示例(XML 配置)
- Gradle–Spring 4 MVC Hello World 示例(@JavaConfig + Servlet 3)
- Maven–Spring 3 MVC Hello World 示例(XML 配置)
- Maven–Spring 3 MVC Hello World 示例(@JavaConfig + Servlet 3)
- 弹簧 3 静止示例(工作)
- 弹簧 4 静止示例(工作)
@Deprecated
–Maven+Spring 2 . 5 . 6 MVC hello world 示例@Deprecated
–Maven+Spring 2 . 5 . 6 MVC hello world 注释示例
新&更新……
- Spring 4 MVC Ajax 示例
- 弹簧 4 表单处理示例
- Spring 4 + Logback 示例
- …
2.处理程序映射
定义 web 请求(URL)如何映射到控制器处理程序。
- BeanNameUrlHandlerMapping 示例
将请求的 URL 映射到 cocntroller 的名称。 - ControllerClassNameHandlerMapping 示例
使用约定将请求的 URL 映射到控制器。 - SimpleUrlHandlerMapping 示例
允许开发者明确指定 URL 模式的映射和处理程序映射。 - 配置处理程序映射优先级
如果应用了多个视图处理程序映射,您必须声明优先级以避免冲突问题。
3.控制器
控制器类来处理 web 请求。
- MultiActionController 示例
将相关动作分组到一个控制器类中。 - MultiActionController 注释示例
多动作控制器通过使用注释,@RequestMapping,他得到了最佳且简单的解决方案。 - properties methodnameresolver 示例
multi action controller 控制器类的一个灵活的方法名解析器,它允许显式定义请求的 URL 和方法名之间的映射。 - ParameterMethodNameResolver 示例
multi action controller 控制器类的另一个方法名解析器,它允许通过请求的参数名将 URL 映射到方法名。 - ParameterizableViewController 示例
有了 ParameterizableViewController,就不再需要在控制器类中硬编码视图名,而是通过 ParameterizableViewController 的“view name”属性来指定视图名。
4.查看解析程序
将从控制器类返回的“视图名称”解析为物理视图页面或 JSP 页面。
- InternalResourceViewResolver 示例
给视图名添加预定义的前缀和后缀(前缀+视图名+后缀),并生成最终的视图页面 URL。 - XmlViewResolver 示例
将视图 beans 放入 XML 文件中。 - ResourceBundleViewResolver 示例
将视图 beans 放入”。属性”文件。 - 配置多视图解析器优先级
如果应用了多视图解析器策略,您必须声明优先级以避免冲突问题。
5.表单处理
Spring MVC 中的表单处理。
- 表单处理示例
Spring MVC 中的表单处理,基于 XML 的版本。 - 表单处理注释示例
Spring MVC 中的表单处理,注释版本。 - 处理重复表单提交
“Post/Redirect/Get”设计模式是这种重复表单提交问题的常用解决方案。 - RedirectView 示例
重定向到另一个绝对、上下文相对或当前请求相对 URL 的视图。 - 处理多页/向导窗体
如何处理多页窗体或向导窗体。
6.Spring 的表单标签库
通过 Spring 的 form 标签呈现 HTML 表单的组件。
- Textbox 示例
<表单:输入/ >标签,呈现一个 HTML textbox 字段。 - 密码示例
<表单:password / >标签,呈现一个 HTML 密码字段。 - Textarea 示例
<表单:textarea / >标签,呈现一个 HTML 的 Textarea 字段。 - 复选框和复选框示例
<表单:复选框/ >,<表单:复选框/ >标签,呈现单个或多个 HTML 复选框。 - Radiobutton 和 Radiobutton 示例
<表单:radiobutton / >,<表单:radio button/>标签,呈现单个或多个 HTML 单选按钮。 - 下拉列表框示例
<表单:select / >,<表单:option / >和<表单:options / >标签,呈现一个 HTML 下拉框、多选框和 list box。 - 隐藏值示例
<表单:hidden / >标签,呈现一个 HTML 隐藏值字段。 - Form errors 标签示例
< form:errors / >标签,呈现那些表单组件的错误消息。 - 文件上传示例
通过 Spring MultipartResolver 进行文件上传处理。
7.将 Spring MVC 与其他框架集成
将 Spring MVC 与其他集成在一起。
- Spring 3 MVC 和 JSR303 @Valid 示例
使用 Hibernate validator (JSR303 实现)来验证 Spring MVC 中的 bean。 - Spring 3 MVC 和 RSS 提要示例
使用 ROME 从 Spring MVC 生成 RSS 提要。 - Spring 3 MVC 和 XML 示例
使用 JAXB 从 Spring MVC 生成 XML 输出。 - Spring 3 MVC 和 JSON 示例
使用 Jackson 从 Spring MVC 生成 JSON 输出。 - 通过 AbstractExcelView
Spring MVC 和 Excel 文件使用 AbstractExcelView 通过 Apache POI 库将数据导出到 Excel 文件。 - 通过 AbstractJExcelView
Spring MVC 和 Excel 文件使用 AbstractJExcelView 通过 JExcelAPI 库将数据导出到 Excel 文件。 - 通过 AbstractPdfView
Spring MVC 和 Pdf 文件使用 abstract PDF view 通过 Bruno Lowagie 的 iText 库将数据导出为 PDF 文件。 - Spring MVC 与 Log4j 集成示例
将 Log4j 集成到 Spring MVC 应用程序中的示例。
8.常见问题
一些常见的使用案例。
- Spring 3 MVC contentnegotiatingviewrolver 示例
这个视图解析器让您根据重复请求文件扩展名来确定将返回哪个视图解析器。 - 异常处理示例
Spring MVC 中的异常处理。 - 处理程序拦截器示例
通过处理程序拦截器拦截 web 请求。 - 国际化示例
Spring MVC 支持多种语言。
10.常见错误
Spring MVC 常见错误及解决方案。
- ModelAndView 的模型值没有通过 el 显示在 JSP 中
- 404 错误代码在 Spring MVC 中不起作用
- 无法更改 HTTP accept 头–使用不同的区域设置解析策略
- Spring MVC 未能转换文件上传表单中的属性值
- 【bean 名称“xxx”的 BindingResult 和 plain target 对象都不能作为请求属性
- ClassNotFoundException:com . sun . syndication . feed . wire feed
- ClassNotFoundException:com . thoughtworks . xstream . io . hierarchical streamreader
Spring Web MVC 参考
- Spring 4.2.x MVC 文档
- Spring 3.2.x MVC 文档
- Spring 2.5.6 MVC 文档
Spring MVC XmlViewResolver 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring-mvc/spring-mvc-xmlviewresolver-example/
在 Spring MVC 中, XmlViewResolver 用于根据 XML 文件中的视图 beans 解析“视图名”。默认情况下,XmlViewResolver
将从 /WEB-INF/views.xml 加载视图 beans,但是,该位置可以通过“ location 属性覆盖:
<beans ...><bean class="org.springframework.web.servlet.view.XmlViewResolver"><property name="location"><value>/WEB-INF/spring-views.xml</value></property></bean>
</beans>
在上面的例子中,它从"/we b-INF/spring-views . XML"加载视图 beans。请参见 XmlViewResolver 示例:
1.控制器
一个控制器类,返回一个视图,名为“ WelcomePage ”。
//...
public class WelcomeController extends AbstractController{@Overrideprotected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse response) throws Exception {ModelAndView model = new ModelAndView("WelcomePage");return model;}
}
2.XmlViewResolver
在 Spring 的 bean 配置文件中注册 XmlViewResolver,从"/we b-INF/Spring-views . XML"加载视图 bean。
<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 class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /><!-- Register the bean --><bean class="com.mkyong.common.controller.WelcomeController" /><bean class="org.springframework.web.servlet.view.XmlViewResolver"><property name="location"><value>/WEB-INF/spring-views.xml</value></property></bean></beans>
3.查看 beans
“视图 bean ”只是在 Spring 的 bean 配置文件中声明的一个普通的 Spring bean,其中
- “ id 是要解析的“视图名称”。
- 类是视图的类型。
- “ url 属性是视图的 url 位置。
文件:spring-views.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-2.5.xsd"><bean id="WelcomePage"class="org.springframework.web.servlet.view.JstlView"><property name="url" value="/WEB-INF/pages/WelcomePage.jsp" /></bean></beans>
How it works ?
When a view name “WelcomPage” is returned by controller, the XmlViewResolver
will find the bean id “WelcomPage” in “spring-views.xml” file, and return the corresponds view’s URL “/WEB-INF/pages/WelcomPage.jsp” back to the DispatcherServlet
.
下载源代码
Download it – SpringMVC-XmlViewResolver-Example.zip (7KB)
参考
- XmlViewResolver 文档
spring mvc xml
SimpleJdbcTemplate 中的 Spring 命名参数示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-named-parameters-examples-in-simplejdbctemplate/
在 JdbcTemplate 中,SQL 参数由一个特殊的占位符“”表示?"符号并按位置装订。问题是每当参数的顺序改变时,你也必须改变参数绑定,这很容易出错,而且维护起来很麻烦。
要解决这个问题,您可以使用“命名的参数,而 SQL 参数是由一个冒号加一个名称来定义的,而不是由位置来定义的。另外,命名参数仅在 SimpleJdbcTemplate 和namedparametejdbctemplate中受支持。
参见下面三个在 Spring 中使用命名参数的例子。
示例 1
演示如何在单个 insert 语句中使用命名参数的示例。
//insert with named parameterpublic void insertNamedParameter(Customer customer){String sql = "INSERT INTO CUSTOMER " +"(CUST_ID, NAME, AGE) VALUES (:custId, :name, :age)";Map<String, Object> parameters = new HashMap<String, Object>();parameters.put("custId", customer.getCustId());parameters.put("name", customer.getName());parameters.put("age", customer.getAge());getSimpleJdbcTemplate().update(sql, parameters);}
示例 2
演示如何在批处理操作语句中使用命名参数的示例。
public void insertBatchNamedParameter(final List<Customer> customers){String sql = "INSERT INTO CUSTOMER " +"(CUST_ID, NAME, AGE) VALUES (:custId, :name, :age)";List<SqlParameterSource> parameters = new ArrayList<SqlParameterSource>();for (Customer cust : customers) {parameters.add(new BeanPropertySqlParameterSource(cust)); }getSimpleJdbcTemplate().batchUpdate(sql,parameters.toArray(new SqlParameterSource[0]));}
示例 3
在批处理操作语句中使用命名参数的另一个例子。
public void insertBatchNamedParameter2(final List<Customer> customers){SqlParameterSource[] params = SqlParameterSourceUtils.createBatch(customers.toArray());getSimpleJdbcTemplate().batchUpdate("INSERT INTO CUSTOMER (CUST_ID, NAME, AGE) VALUES (:custId, :name, :age)",params);}
下载源代码
Download it – Spring-JDBC-Named-Parameter-Example.zip (15 KB)Tags : jdbc spring
Spring 对象/XML 映射示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-objectxml-mapping-example/
Spring 的对象/XML 映射将对象转换成 XML,反之亦然。这个过程也称为
- XML 编组–将对象转换为 XML。
- XML 解组–将 XML 转换成对象。
在本教程中,我们将向您展示如何使用 Spring 的 oxm 来进行转换,对象< - Spring oxm - > XML 。
Note
No nonsense, for why and what benefits of using Spring’s oxm, read this official Spring Object/XML mapping article.
1.项目依赖性
本例中的依赖关系。
Note
Spring’s oxm itself doesn’t handle the XML marshalling or UnMarshalling, it depends developer to inject their prefer XML binding framework. In this case, you will use Castor binding framework.
<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-context</artifactId><version>${spring.version}</version></dependency><!-- spring oxm --><dependency><groupId>org.springframework</groupId><artifactId>spring-oxm</artifactId><version>${spring.version}</version></dependency><!-- Uses Castor for XML --><dependency><groupId>org.codehaus.castor</groupId><artifactId>castor</artifactId><version>1.2</version></dependency><!-- Castor need this --><dependency><groupId>xerces</groupId><artifactId>xercesImpl</artifactId><version>2.8.1</version></dependency></dependencies>
2.简单对象
一个简单的对象,后来把它转换成 XML 文件。
package com.mkyong.core.model;public class Customer {String name;int age;boolean flag;String address;//standard getter, setter and toString() methods.
}
3.编组器和解组器
这个类将通过 Spring 的 oxm 接口:Marshaller
和Unmarshaller
处理转换。
package com.mkyong.core;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;public class XMLConverter {private Marshaller marshaller;private Unmarshaller unmarshaller;public Marshaller getMarshaller() {return marshaller;}public void setMarshaller(Marshaller marshaller) {this.marshaller = marshaller;}public Unmarshaller getUnmarshaller() {return unmarshaller;}public void setUnmarshaller(Unmarshaller unmarshaller) {this.unmarshaller = unmarshaller;}public void convertFromObjectToXML(Object object, String filepath)throws IOException {FileOutputStream os = null;try {os = new FileOutputStream(filepath);getMarshaller().marshal(object, new StreamResult(os));} finally {if (os != null) {os.close();}}}public Object convertFromXMLToObject(String xmlfile) throws IOException {FileInputStream is = null;try {is = new FileInputStream(xmlfile);return getUnmarshaller().unmarshal(new StreamSource(is));} finally {if (is != null) {is.close();}}}}
4.弹簧配置
在 Spring 的 bean 配置文件中,注入CastorMarshaller
作为 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-3.0.xsd"><bean id="XMLConverter" class="com.mkyong.core.XMLConverter"><property name="marshaller" ref="castorMarshaller" /><property name="unmarshaller" ref="castorMarshaller" /></bean><bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" /></beans>
5.试验
运行它。
package com.mkyong.core;import java.io.IOException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mkyong.core.model.Customer;public class App {private static final String XML_FILE_NAME = "customer.xml";public static void main(String[] args) throws IOException {ApplicationContext appContext = new ClassPathXmlApplicationContext("App.xml");XMLConverter converter = (XMLConverter) appContext.getBean("XMLConverter");Customer customer = new Customer();customer.setName("mkyong");customer.setAge(30);customer.setFlag(true);customer.setAddress("This is address");System.out.println("Convert Object to XML!");//from object to XML fileconverter.convertFromObjectToXML(customer, XML_FILE_NAME);System.out.println("Done \n");System.out.println("Convert XML back to Object!");//from XML to objectCustomer customer2 = (Customer)converter.convertFromXMLToObject(XML_FILE_NAME);System.out.println(customer2);System.out.println("Done");}
}
输出
Convert Object to XML!
Done Convert XML back to Object!
Customer [name=mkyong, age=30, flag=true, address=This is address]
Done
下面的 XML 文件" customer.xml 在您的项目根文件夹中生成。
文件:customer.xml
<?xml version="1.0" encoding="UTF-8"?>
<customer flag="true" age="30"><address>This is address</address><name>mkyong</name>
</customer>
Castor XML 映射
等等,为什么旗帜和年龄转换成属性?这是一种控制哪个字段应该用作属性或元素的方法吗?当然,您可以使用 [Castor XML 映射](http://web.archive.org/web/20190223073326/http://www.castor.org/xml-mapping.html target=)来定义对象和 XML 之间的关系。
创建以下映射文件,并将其放入项目类路径中。
文件:mapping.xml
<mapping><class name="com.mkyong.core.model.Customer"><map-to xml="customer" /><field name="age" type="integer"><bind-xml name="age" node="attribute" /></field><field name="flag" type="boolean"><bind-xml name="flag" node="element" /></field><field name="name" type="string"><bind-xml name="name" node="element" /></field><field name="address" type="string"><bind-xml name="address" node="element" /></field></class>
</mapping>
在 Spring bean 配置文件中,通过“ mappingLocation 将上述 mapping.xml 注入到 CastorMarshaller 中。
<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-3.0.xsd"><bean id="XMLConverter" class="com.mkyong.core.XMLConverter"><property name="marshaller" ref="castorMarshaller" /><property name="unmarshaller" ref="castorMarshaller" /></bean><bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" ><property name="mappingLocation" value="classpath:mapping.xml" /></bean></beans>
再次测试,XML 文件“ customer.xml ”将被更新。
文件:customer.xml
<?xml version="1.0" encoding="UTF-8"?>
<customer age="30"><flag>true</flag><name>mkyong</name><address>This is address</address>
</customer>
下载源代码
Download it – Spring3-Object-XML-Mapping-Example.zip (7 KB)
参考
- Castor XML 映射
- Spring 对象/XML 映射引用
oxm spring3
Spring @PostConstruct 和@PreDestroy 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-postconstruct-and-predestroy-example/
在 Spring 中,可以实现 InitializingBean 和 DisposableBean 接口,也可以在 Bean 配置文件中指定 init-method 和 destroy-method 用于初始化和销毁回调函数。在本文中,我们将向您展示如何使用注释 @PostConstruct 和 @PreDestroy 来做同样的事情。
Note
The @PostConstruct and @PreDestroy annotation are not belong to Spring, it’s located in the J2ee library – common-annotations.jar.
@PostConstruct 和@PreDestroy
带有@PostConstruct 和@PreDestroy 批注的 CustomerService bean
package com.mkyong.customer.services;import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;public class CustomerService
{String message;public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}@PostConstructpublic void initIt() throws Exception {System.out.println("Init method after properties are set : " + message);}@PreDestroypublic void cleanUp() throws Exception {System.out.println("Spring Container is destroy! Customer clean up");}}
默认情况下,Spring 不知道@PostConstruct 和@PreDestroy 注释。要启用它,您必须注册'commannotationbeanpostprocessor,或者在 bean 配置文件中指定'context:annotation-config/'。
1.commannotationbeanpostprocessor
<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.context.annotation.CommonAnnotationBeanPostProcessor" /><bean id="customerService" class="com.mkyong.customer.services.CustomerService"><property name="message" value="i'm property message" /></bean></beans>
2.
<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="customerService" class="com.mkyong.customer.services.CustomerService"><property name="message" value="i'm property message" /></bean></beans>
运行它
package com.mkyong.common;import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.mkyong.customer.services.CustomerService;public class App
{public static void main( String[] args ){ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"Spring-Customer.xml"});CustomerService cust = (CustomerService)context.getBean("customerService");System.out.println(cust);context.close();}
}
输出
Init method after properties are set : im property message
com.mkyong.customer.services.CustomerService@47393f
...
INFO: Destroying singletons in org.springframework.beans.factory.
support.DefaultListableBeanFactory@77158a:
defining beans [customerService]; root of factory hierarchy
Spring Container is destroy! Customer clean up
设置消息属性后,调用 initIt()方法(@PostConstruct) ,在 context.close()后调用 cleanUp()方法(@ PreDestroy);
下载源代码
Download It – Spring-PostConstruct-PreDestroy-Example.zipspring
Spring 属性依赖检查
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-properties-dependency-checking/
在 Spring 中,您可以使用依赖检查特性来确保已经设置或注入了所需的属性。
依赖性检查模式
支持 4 种依赖检查模式:
- none–不进行依赖性检查。
- 简单——如果原始类型(int,long,double…)和集合类型(map,list..)尚未设置,将引发 UnsatisfiedDependencyException。
- objects–如果尚未设置对象类型的任何属性,将引发 UnsatisfiedDependencyException。
- all–如果尚未设置任何类型的任何属性,将抛出一个 UnsatisfiedDependencyException
。
P.S 默认模式为无
例子
演示的客户和人员对象。
package com.mkyong.common;public class Customer
{private Person person;private int type;private String action;//getter and setter methods
}
package com.mkyong.common;public class Person
{private String name;private String address;private int age;//getter and setter methods
}
1.无依赖性检查
具有“无”依赖性检查模式的 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 id="CustomerBean" class="com.mkyong.common.Customer" ><property name="action" value="buy" /></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.简单的依赖性检查
具有“简单”依赖检查模式的 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 id="CustomerBean" class="com.mkyong.common.Customer" dependency-check="simple"><property name="person" ref="PersonBean" /><property name="action" value="buy" /></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>
尚未设置“类型”属性(基本类型或集合类型),将引发一个UnsatisfiedDependencyException。
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'CustomerBean'
defined in class path resource [config/Spring-Customer.xml]:
Unsatisfied dependency expressed through bean property 'type':
Set this property value or disable dependency checking for this bean.
3.对象依赖性检查
具有“对象”依赖性检查模式的 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 id="CustomerBean" class="com.mkyong.common.Customer" dependency-check="objects"><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>
“人员”属性(对象类型)尚未设置,将引发一个UnsatisfiedDependencyException。
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'CustomerBean'
defined in class path resource [config/Spring-Customer.xml]:
Unsatisfied dependency expressed through bean property 'person':
Set this property value or disable dependency checking for this bean.
4.所有依赖性检查
具有“全部”依赖性检查模式的 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 id="CustomerBean" class="com.mkyong.common.Customer" dependency-check="all"><property name="action" value="buy" /></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>
“简单”和“对象”模式的组合,如果任何类型(原语、集合和对象)的任何属性尚未设置,将会抛出一个UnsatisfiedDependencyException。
全局默认依赖性检查
为每个 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" default-dependency-check="all"><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>
此配置文件中声明的所有 beans 都默认为“All”依赖项检查模式。
@Required Annotation
In most scenarios, you just need to make sure a particular property has been set, but not all properties of a certain types (primitive, collection or object). The @Required Annotation can enforce this checking, see detail.spring
spring propertyplaceholderconfigure 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-propertyplaceholderconfigurer-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"><bean id="customerDAO" class="com.mkyong.customer.dao.impl.JdbcCustomerDAO"><property name="dataSource" ref="dataSource" /></bean><bean id="customerSimpleDAO" class="com.mkyong.customer.dao.impl.SimpleJdbcCustomerDAO"><property name="dataSource" ref="dataSource" /></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/mkyongjava" /><property name="username" value="root" /><property name="password" value="password" /></bean></beans>
但是,在企业环境中,部署详细信息通常只能由您的系统或数据库管理员“接触”,他们只是拒绝直接访问您的 bean 配置文件,并且他们会请求一个单独的文件用于部署配置,例如,一个简单的属性,仅包含部署详细信息。
PropertyPlaceholderConfigurer 示例
要修复它,您可以使用PropertyPlaceholderConfigurer类将部署细节外部化到一个属性文件中,并通过一种特殊的格式-$ { variable }从 bean 配置文件中访问。
创建一个属性文件(database.properties),包含您的数据库详细信息,将其放入您的项目类路径中。
jdbc.driverClassName=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/mkyongjavajdbc.username=rootjdbc.password=password
在 bean 配置文件中声明一个PropertyPlaceholderConfigurer,并映射到您刚才创建的“database.properties
”属性文件。
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="location"><value>database.properties</value></property></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"><beanclass="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="location"><value>database.properties</value></property></bean><bean id="customerDAO" class="com.mkyong.customer.dao.impl.JdbcCustomerDAO"><property name="dataSource" ref="dataSource" /></bean><bean id="customerSimpleDAO" class="com.mkyong.customer.dao.impl.SimpleJdbcCustomerDAO"><property name="dataSource" ref="dataSource" /></bean><bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driverClassName}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></bean></beans>
Alternative usage
You also can use PropertyPlaceholderConfigurer to share some constant variables to all other beans. For example, define your log file location in a properties file, and access the properties value from different beans configuration files via ${log.filepath}
. ## 下载源代码
Download it – Spring-JDBC-PropertyPlaceholderConfigurer-Example.zipspring (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/20190210020435/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
Spring @PropertySource 示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/spring/spring-propertysources-example/
在 Spring 中,您可以使用@PropertySource
注释将您的配置具体化到一个属性文件中。在本教程中,我们将向您展示如何使用@PropertySource
来读取属性文件,并使用@Value
和Environment
来显示值。
P.S @PropertySource 从 3.1 春开始可用
1.@PropertySource 和@Value
一个经典的例子,读取一个属性文件,用${}
显示。
config.properties
mongodb.url=1.2.3.4
mongodb.db=hello
AppConfigMongoDB
package com.mkyong.config;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
//...@Configuration
@ComponentScan(basePackages = { "com.mkyong.*" })
@PropertySource("classpath:config.properties")
public class AppConfigMongoDB {//1.2.3.4@Value("${mongodb.url}")private String mongodbUrl;//hello@Value("${mongodb.db}")private String defaultDb;@Beanpublic MongoTemplate mongoTemplate() throws Exception {MongoClientOptions mongoOptions = new MongoClientOptions.Builder().maxWaitTime(1000 * 60 * 5).build();MongoClient mongo = new MongoClient(mongodbUrl, mongoOptions);MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongo, defaultDb);return new MongoTemplate(mongoDbFactory);}//To resolve ${} in @Value@Beanpublic static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {return new PropertySourcesPlaceholderConfigurer();}}
Note
To resolve ${} in @Values
, you must register a static PropertySourcesPlaceholderConfigurer
in either XML or annotation configuration file.freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });
2.@属性源和环境
Spring 建议使用Environment
来获取属性值。
AppConfigMongoDB
package com.mkyong.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
//...@Configuration
@ComponentScan(basePackages = { "com.mkyong.*" })
@PropertySource("classpath:config.properties")
public class AppConfigMongoDB {@Autowiredprivate Environment env;@Beanpublic MongoTemplate mongoTemplate() throws Exception {String mongodbUrl = env.getProperty("mongodb.url");String defaultDb = env.getProperty("mongodb.db");MongoClientOptions mongoOptions = new MongoClientOptions.Builder().maxWaitTime(1000 * 60 * 5).build();MongoClient mongo = new MongoClient(mongodbUrl, mongoOptions);MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongo, defaultDb);return new MongoTemplate(mongoDbFactory);}}
3.更多@PropertySource 示例
比较常见的例子。
3.1 在@PropertySource
资源位置内解析${}的示例。
@Configuration@PropertySource("file:${app.home}/app.properties")public class AppConfig {@AutowiredEnvironment env;}
启动时设置系统属性。
System.setProperty("app.home", "test");java -jar -Dapp.home="/home/mkyon/test" example.jar
3.2 包括多个属性文件。
@Configuration@PropertySource({"classpath:config.properties","classpath:db.properties" //if same key, this will 'win'})public class AppConfig {@AutowiredEnvironment env;}
Note
If a property key is duplicated, the last declared file will ‘win’ and override.
4.Spring 4 和@PropertySources
Spring 4 上的一些增强。
4.1 引入了新的@PropertySources
来支持 Java 8 和更好的方法来包含多个属性文件。
@Configuration@PropertySources({@PropertySource("classpath:config.properties"),@PropertySource("classpath:db.properties")})public class AppConfig {//...}
4.2 允许@PropertySource
忽略未找到的属性文件。
@Configuration@PropertySource("classpath:missing.properties")public class AppConfig {//...}
如果没有找到missing.properties
,系统无法启动并抛出FileNotFoundException
Caused by: java.io.FileNotFoundException: class path resource [missiong.properties] cannot be opened because it does not exist
在 Spring 4 中,您可以使用ignoreResourceNotFound
来忽略未找到的属性文件
@Configuration@PropertySource(value="classpath:missing.properties", ignoreResourceNotFound=true)public class AppConfig {//...}
@PropertySources({@PropertySource(value = "classpath:missing.properties", ignoreResourceNotFound=true),@PropertySource("classpath:config.properties")})
完成了。
参考
- Sprong IO–property source
- Spring IO–property sources
- 弹簧 IO–配置
- Spring @Value 默认值
- 春季支尔格:SPR-8539
Tags : spring spring3 spring4freestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });
Spring 3 + Quartz 1.8.6 调度器示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/spring-quartz-scheduler-example/
【2012 年 7 月 25 日更新–升级文章以使用 Spring 3 和 Quartz 1.8.6(原来是 Spring 2.5.6 和 Quartz 1.6)
在本教程中,我们将向您展示如何将 Spring 与 Quartz scheduler 框架集成。Spring 附带了许多方便的类来支持 Quartz,并将您的类解耦到 Quartz APIs。
使用的工具:
- 释放弹簧
- 石英
- Eclipse 4.2
- maven3
Why NOT Quartz 2?
Currently, Spring 3 is still NOT support Quartz 2 APIs, see this SPR-8581 bug report. Will update this article again once bug fixed is released.
1.项目依赖性
集成 Spring 3 和 Quartz 1.8.6 需要以下依赖项
文件:pom.xml
...
<dependencies><!-- Spring 3 dependencies --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>3.1.2.RELEASE</version></dependency><!-- QuartzJobBean in spring-context-support.jar --><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>3.1.2.RELEASE</version></dependency><!-- Spring + Quartz need transaction --><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>3.1.2.RELEASE</version></dependency><!-- Quartz framework --><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>1.8.6</version></dependency></dependencies>
...
2.调度程序任务
创建一个普通的 Java 类,这是您想要在 Quartz 中调度的类。
文件:RunMeTask.java
package com.mkyong.common;public class RunMeTask {public void printMe() {System.out.println("Spring 3 + Quartz 1.8.6 ~");}
}
3.声明 Quartz 调度程序作业
使用 Spring,您可以通过两种方式声明 Quartz 作业:
3.1 MethodInvokingJobDetailFactoryBean
这是最简单直接的方法,适合简单的调度器。
<bean id="runMeJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"><property name="targetObject" ref="runMeTask" /><property name="targetMethod" value="printMe" /></bean>
3.2 JobDetailBeanT5QuartzJobBean
更加灵活,适合复杂的调度器。你需要创建一个扩展 Spring 的QuartzJobBean
类,并在executeInternal()
方法中定义你想要调度的方法,并通过 setter 方法传递调度器任务(RunMeTask)。
文件:RunMeJob.java
package com.mkyong.common;import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;public class RunMeJob extends QuartzJobBean {private RunMeTask runMeTask;public void setRunMeTask(RunMeTask runMeTask) {this.runMeTask = runMeTask;}protected void executeInternal(JobExecutionContext context)throws JobExecutionException {runMeTask.printMe();}
}
通过jobClass
配置目标类,通过jobDataAsMap
配置方法运行。
<bean name="runMeJob" class="org.springframework.scheduling.quartz.JobDetailBean"><property name="jobClass" value="com.mkyong.common.RunMeJob" /><property name="jobDataAsMap"><map><entry key="runMeTask" value-ref="runMeTask" /></map></property></bean>
4.引发
配置 Quartz 触发器以定义何时运行调度程序作业。支持两种类型触发器:
4.1 SimpleTrigger
它允许设置运行作业的开始时间、结束时间、重复间隔。
<!-- Simple Trigger, run every 5 seconds --><bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"><property name="jobDetail" ref="runMeJob" /><property name="repeatInterval" value="5000" /><property name="startDelay" value="1000" /></bean>
4.2 CronTrigger
它允许 Unix cron 表达式指定运行作业的日期和时间。
<!-- Cron Trigger, run every 5 seconds --><bean id="cronTrigger"class="org.springframework.scheduling.quartz.CronTriggerBean"><property name="jobDetail" ref="runMeJob" /><property name="cronExpression" value="0/5 * * * * ?" /></bean>
Note
The Unix cron expression is highly flexible and powerful, read more in following websites :
- http://en . Wikipedia . org/wiki/cron _ expression
- http://www.quartz-scheduler.org/docs/examples/Example3.html
5.调度程序工厂
创建一个调度器工厂 bean,将作业细节和触发器集成在一起。
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"><property name="jobDetails"><list><ref bean="runMeJob" /></list></property><property name="triggers"><list><ref bean="simpleTrigger" /></list></property></bean>
6.Spring Bean 配置文件
完成 Spring 的 bean 配置文件。
文件:Spring-Quartz.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-3.0.xsd"><bean id="runMeTask" class="com.mkyong.common.RunMeTask" /><!-- Spring Quartz --><bean name="runMeJob" class="org.springframework.scheduling.quartz.JobDetailBean"><property name="jobClass" value="com.mkyong.common.RunMeJob" /><property name="jobDataAsMap"><map><entry key="runMeTask" value-ref="runMeTask" /></map></property></bean><!-- <bean id="runMeJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="runMeTask" /> <property name="targetMethod" value="printMe" /> </bean> --><!-- Simple Trigger, run every 5 seconds --><bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"><property name="jobDetail" ref="runMeJob" /><property name="repeatInterval" value="5000" /><property name="startDelay" value="1000" /></bean><!-- Cron Trigger, run every 5 seconds --><bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"><property name="jobDetail" ref="runMeJob" /><property name="cronExpression" value="0/5 * * * * ?" /></bean><bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"><property name="jobDetails"><list><ref bean="runMeJob" /></list></property><property name="triggers"><list><ref bean="simpleTrigger" /></list></property></bean></beans>
7.演示
跑吧~
package com.mkyong.common;import org.springframework.context.support.ClassPathXmlApplicationContext;public class App
{public static void main( String[] args ) throws Exception{new ClassPathXmlApplicationContext("Spring-Quartz.xml");}
}
输出到控制台。
Jul 25, 2012 3:23:09 PM org.springframework.scheduling.quartz.SchedulerFactoryBean startScheduler
INFO: Starting Quartz Scheduler now
Spring 3 + Quartz 1.8.6 ~ //run every 5 seconds
Spring 3 + Quartz 1.8.6 ~
下载源代码
Download it – Spring3-Quartz-Example.zip (25 KB)
参考
- 使用带弹簧的石英调度器
- 石英官网
- 支柱 2 +弹簧 3 +石英 1.8 示例
Tags : integration quartz scheduler spring spring3
相关文章
-
Struts 1+Spring 2 . 5 . 6+Quartz 1.6 调度器 exa
-
Struts 2+Spring 2 . 5 . 6+Quartz 1.6 调度器 int
-
Spring + JDK 定时器调度器示例
-
Struts 2 + Quartz 2 调度器集成示例
-
Struts 2 + Spring 3 + Quartz 1.8 调度器示例
-
JSF 2 +春天 3 整合实例
-
Quartz 1.6 调度器教程
-
石英 2 调度器教程
-
Quartz 2 JobListener 示例
-
在 Quartz 中运行多个作业的示例