如何:从Spring 4.0快速入门以构建简单的REST-Like API(演练)

关于使用Spring MVC创建Web API的另一篇教程。 不太复杂。 只是一个演练。 生成的应用程序将提供简单的API,将Mongo作为其持久性,并将通过Spring Security进行保护。

入门– POM

当然,我仍然是Maven的忠实拥护者,因此该项目基于Maven。 既然有可用的Spring 4.0 RC2,我决定使用其新的依赖项管理,从而产生以下pom.xml:转到Spring MVC应用程序非常简单。 新的东西是dependencyManagement元素。 对此的更多说明可以在这里找到: http : //spring.io/blog/2013/12/03/spring-framework-4-0-rc2-available

组态

使用JavaConfig配置该应用程序。 我将其分为几个部分:

服务配置

@Configuration
public class ServicesConfig {@Autowiredprivate AccountRepository accountRepository;@Beanpublic UserService userService() {return new UserService(accountRepository);}@Beanpublic PasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();}
}

没有组件扫描。 真的很简单。

持久性配置

具有所有可用存储库的MongoDB配置。 在这个简单的应用程序中,我们只有一个存储库,因此配置非常简单。

@Configuration
class PersistenceConfig {@Beanpublic AccountRepository accountRepository() throws UnknownHostException {return new MongoAccountRepository(mongoTemplate());}@Beanpublic MongoDbFactory mongoDbFactory() throws UnknownHostException {return new SimpleMongoDbFactory(new Mongo(), "r");}@Beanpublic MongoTemplate mongoTemplate() throws UnknownHostException {MongoTemplate template = new MongoTemplate(mongoDbFactory(), mongoConverter());return template;}@Beanpublic MongoTypeMapper mongoTypeMapper() {return new DefaultMongoTypeMapper(null);}@Beanpublic MongoMappingContext mongoMappingContext() {return new MongoMappingContext();}@Beanpublic MappingMongoConverter mongoConverter() throws UnknownHostException {MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), mongoMappingContext());converter.setTypeMapper(mongoTypeMapper());return converter;}
}

安全配置

从理论上讲,Spring Security 3.2可以使用JavaConfig进行完全配置。 对我来说,这仍然是一种理论,因此我在这里使用XML:

@Configuration
@ImportResource("classpath:spring-security-context.xml")
public class SecurityConfig {}

XML:如您所见,API将使用基本身份验证。

WebAppInitializer

我们不需要web.xml,因此我们使用以下代码来配置Web应用程序:

@Order(2)
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}@Overrideprotected Class[] getRootConfigClasses() {return new Class[] {ServicesConfig.class, PersistenceConfig.class, SecurityConfig.class};}@Overrideprotected Class[] getServletConfigClasses() {return new Class[] {WebMvcConfig.class};}@Overrideprotected Filter[] getServletFilters() {CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();characterEncodingFilter.setEncoding("UTF-8");characterEncodingFilter.setForceEncoding(true);return new Filter[] {characterEncodingFilter};}@Overrideprotected void customizeRegistration(ServletRegistration.Dynamic registration) {        registration.setInitParameter("spring.profiles.active", "default");}
}

WebAppSecurityInitializer

Spring Security的新功能3。

@Order(1)
public class WebAppSecurityInitializer extends AbstractSecurityWebApplicationInitializer {}

WebMvcConfig

调度程序Servlet配置。 真的很基础。 只有关键组件才能构建简单的API。

@Configuration
@ComponentScan(basePackages = { "pl.codeleak.r" }, includeFilters = {@Filter(value = Controller.class)})
public class WebMvcConfig extends WebMvcConfigurationSupport {private static final String MESSAGE_SOURCE = "/WEB-INF/i18n/messages";@Overridepublic RequestMappingHandlerMapping requestMappingHandlerMapping() {RequestMappingHandlerMapping requestMappingHandlerMapping = super.requestMappingHandlerMapping();requestMappingHandlerMapping.setUseSuffixPatternMatch(false);requestMappingHandlerMapping.setUseTrailingSlashMatch(false);return requestMappingHandlerMapping;}@Bean(name = "messageSource")public MessageSource messageSource() {ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();messageSource.setBasename(MESSAGE_SOURCE);messageSource.setCacheSeconds(5);return messageSource;}@Overridepublic Validator getValidator() {LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();validator.setValidationMessageSource(messageSource());return validator;}@Overridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();}
}

这就是配置。 简单。

索引控制器

为了验证配置是否正确,我创建了一个IndexController,它提供简单的“ Hello,World”之类的文本:

@Controller
@RequestMapping("/")
public class IndexController {@RequestMapping@ResponseBodypublic String index() {return "This is an API endpoint.";}
}

运行应用程序时,您应该在浏览器中看到此文本。

构建API

用户服务

要完成Spring Security配置,实际上实际上仍然需要一部分:UserService哪个实例是先前创建的:

public class UserService implements UserDetailsService {private AccountRepository accountRepository;public UserService(AccountRepository accountRepository) {this.accountRepository = accountRepository;}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {Account account = accountRepository.findByEmail(username);if(account == null) {throw new UsernameNotFoundException("user not found");}return createUser(account);}public void signin(Account account) {SecurityContextHolder.getContext().setAuthentication(authenticate(account));}private Authentication authenticate(Account account) {return new UsernamePasswordAuthenticationToken(createUser(account), null, Collections.singleton(createAuthority(account)));  }private User createUser(Account account) {return new User(account.getEmail(), account.getPassword(), Collections.singleton(createAuthority(account)));}private GrantedAuthority createAuthority(Account account) {return new SimpleGrantedAuthority(account.getRole());}}

要求是建立一个处理3种方法的API端点:获取当前登录的用户,获取所有用户(不是很安全),创建新帐户。 因此,让我们开始吧。

帐户

该帐户将是我们的第一个Mongo文档。 这真的很容易:

@SuppressWarnings("serial")
@Document
public class Account implements java.io.Serializable {@Idprivate String objectId;@Email@Indexed(unique = true)private String email;@JsonIgnore@NotBlankprivate String password;private String role = "ROLE_USER";private Account() {}public Account(String email, String password, String role) {this.email = email;this.password = password;this.role = role;}// getters and setters
}

资料库

我从界面开始:

public interface AccountRepository {Account save(Account account);List findAll();Account findByEmail(String email);
}

以及后来的Mongo实现:

public class MongoAccountRepository implements AccountRepository {private MongoTemplate mongoTemplate;public MongoAccountRepository(MongoTemplate mongoTemplate) {this.mongoTemplate = mongoTemplate;}@Overridepublic Account save(Account account) {mongoTemplate.save(account);return account;}@Overridepublic List findAll() {return mongoTemplate.findAll(Account.class);}@Overridepublic Account findByEmail(String email) {return mongoTemplate.findOne(Query.query(Criteria.where("email").is(email)), Account.class);}
}

API控制器

所以我们快到了。 我们需要将内容提供给用户。 因此,让我们创建端点:

@Controller
@RequestMapping("api/account")
class AccountController {private AccountRepository accountRepository;@Autowiredpublic AccountController(AccountRepository accountRepository) {this.accountRepository = accountRepository;}@RequestMapping(value = "current", method = RequestMethod.GET)@ResponseStatus(value = HttpStatus.OK)@ResponseBody@PreAuthorize(value = "isAuthenticated()")public Account current(Principal principal) {Assert.notNull(principal);return accountRepository.findByEmail(principal.getName());}@RequestMapping(method = RequestMethod.GET)@ResponseStatus(value = HttpStatus.OK)@ResponseBody@PreAuthorize(value = "isAuthenticated()")public Accounts list() {List accounts = accountRepository.findAll();return new Accounts(accounts);}@RequestMapping(method = RequestMethod.POST)@ResponseStatus(value = HttpStatus.CREATED)@ResponseBody@PreAuthorize(value = "permitAll()")public Account create(@Valid Account account) {accountRepository.save(account);return account;}private class Accounts extends ArrayList {public Accounts(List accounts) {super(accounts);}}
}

希望您注意到我们直接与存储库进行通讯,因此不会对密码进行编码。 如果需要,可以稍后修复一些小细节。 现在可以了。

整理起来

我最后需要的是一些错误处理程序,以便使用者可以用JSON而不是HTML看到错误消息。 使用Spring MVC和@Controller建议,这很简单。

@ControllerAdvice
public class ErrorHandler {@ExceptionHandler(value = Exception.class)@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic ErrorResponse errorResponse(Exception exception) {return new ErrorResponse(exception.getMessage());}}public class ErrorResponse {private String message;public ErrorResponse(String message) {this.message = message;}public String getMessage() {return message;}
}

如果您想在Spring 4中看到@ControllerAdvice的更多高级用法,请阅读
这个帖子 。

测试应用

作为一个单元测试极客,我应该首先创建单元测试。 但是……我只是想测试一个新工具:Postman(Chrome扩展程序)。 所以我做了:

获取帐户(未授权):

邮政帐户(不需要身份验证:

获取帐户(授权):

获取当前帐户(授权):

我们完了

现在就这样。 希望您喜欢我喜欢创建该项目。 这个项目和这篇文章总共花了我大约3个小时。 我大部分时间都花在弄清楚安全性配置上(我希望它完全使用Java)并编写此演练。

参考:操作方法:从我们的JCG合作伙伴 Rafal Borowiec在Codeleak.pl博客上快速开始于Spring 4.0,以构建一个简单的REST-Like API(演练) 。

翻译自: https://www.javacodegeeks.com/2013/12/how-to-get-started-quickly-with-spring-4-0-to-build-a-simple-rest-like-api-walkthrough.html

如何:从Spring 4.0快速入门以构建简单的REST-Like API(演练)相关推荐

  1. SpringBoot整合BeetlSql3.0及BeetlSql3.0快速入门说明

    一 SpringBoot整合BeetlSql3.0 1.1 加入依赖 <dependencies><dependency><groupId>org.springfr ...

  2. Spring学习(1)——快速入门

    Spring学习(1)--快速入门 认识 Spring 框架 Spring 框架是 Java 应用最广的框架,它的成功来源于理念,而不是技术本身,它的理念包括 IoC (Inversion of Co ...

  3. Castle Active Record for .NET2.0快速入门示例

    一.创建Web工程 创建一个Web站点或者Web应用程序,添加对Castle.ActiveRecord.dll的引用. 二.创建需要持久化的业务实体 在.NET2.0下,由于引入了泛型,创建业务实体比 ...

  4. Spring Boot的快速入门

    Spring Boot的快速入门 1.导入第一个maven项目 自动生成maven项目 2.了解maven项目结构 3.启动服务 和普通maven项目结构是一样的,值得注意的是,启动服务的入口是 ![ ...

  5. Spring MVC 4快速入门Maven原型已改进

    Spring Boot使Spring入门非常容易. 但是仍然有人对不使用Spring Boot并以更经典的方式引导应用程序感兴趣. 几年前,我创建了一个原型(早于Spring Boot),简化了引导S ...

  6. TensorFlow 2.0 快速入门指南 | iBooker·ApacheCN

    原文:TensorFlow 2.0 Quick Start Guide 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 不要担心自己的形象,只关心如何实现目标.--<原则>,生活 ...

  7. 《R语言编程艺术》——第1章 1.0 快速入门

    第1章 1.0 快速入门 如前言所述,R是一种针对统计分析和数据科学的功能全面的开源统计语言.它在商业.工业.政府部门.医药和科研等涉及数据分析的领域都有广泛的应用. 本章将给出R的简单介绍--如何调 ...

  8. 视频教程-沐风老师Scratch3.0快速入门视频课程-其他

    沐风老师Scratch3.0快速入门视频课程 沐风课堂创始人,专栏作家,独立媒体人,资深互联网从业者. 沐风老师 ¥20.00 立即订阅 扫码下载「CSDN程序员学院APP」,1000+技术好课免费看 ...

  9. RHEL8.0快速入门系列笔记--理论知识储备(一)

    RHEL8.0快速入门系列笔记–理论知识储备(一) 红帽公司发布Linux8.0系统已经有一段时间,最近准备学习关于RHEL8.0的相关新特性.根据官方介绍:RHEL8.0在云/容器化工作负载方面做了 ...

最新文章

  1. capistrano
  2. MongoDB在不同主机间复制数据库和集合的教程_MongoDB_脚本之家
  3. JMeter基础知识
  4. Effective C++学习第二天
  5. Java设计模式 - 示例教程
  6. 支付宝公布“五一”出境游报告:国人太能花钱了
  7. 《社交网站界面设计(原书第2版)》——3.2 注册
  8. poj2485poj2395 kruskal
  9. leetcode探索动态规划(三)
  10. Qt安装与使用(小白专用教程)
  11. matlab正弦函数傅里叶变换,正弦函数及其傅里叶变换 二
  12. 手机版wps怎么制作折线图_PPT制作必修课下载-PPT制作必修课app官方版v1.0手机版下载...
  13. office安装下载
  14. 概率论 随机变量及常用6大分布整理
  15. 如何理解GPO版本号
  16. 从零开始perp交叉编译及配置
  17. 单元测试、注解、枚举、反射(5)JavaSE
  18. linux debian iso下载,Debian GNU/Linux 9.8 “Stretch” live和DVD ISO现在可供下载
  19. 最短路:迪杰斯特拉算法
  20. 析取 为什么是并集 合取

热门文章

  1. Hibernate框架(1)
  2. 量子计算机对人类长寿,科学家称“极端长寿”在未来几十年可能会达到新的里程碑...
  3. php破坏代码,php不破坏单词截取子字符串
  4. 怎样批量获取文件名,批量提取文件名 文件名读取windows 批处理文件
  5. php 错误提示开启,php开启与关闭错误提示,php开启错误提示_PHP教程
  6. 服务器 .err文件,IIS 关闭HTTPERR(IIS日志)的方法
  7. python遗传算法工具箱的使用_遗传算法的python实现,非常值得看的一篇文章
  8. 转: 虚拟IP(VIP)原理
  9. mqtt java_MQTT和Java入门
  10. react性能优化方案_React灵敏且性能卓越的Spray + Akka解决方案,以“在Java和Node.js中发挥并发性和性能”...