大家好 我们向学生的专业假期表示祝贺,并通知我们,二月份我们将开始
“ Spring Framework开发人员 ”课程! 这将是今天出版的主题。
正义联盟(Justice League)处于危险之中,只有阿尔弗雷德(Alfred)可以挽救所有人-借助带有Spring Boot,Spring Data和MongoDB的新管理系统。
对于正义联盟来说,当可怕的黑暗之地决定奴役人类时,黑暗时代已经来临。 蝙蝠侠和神奇女侠开始寻找联盟成员,仅缺少一个要点-正义联盟成员的适当管理制度。

没有足够的时间从头开始创建一个庞大的项目,因此蝙蝠侠将这项艰巨的任务转移给了他亲爱的阿尔弗雷德(毕竟罗宾太不可预测了),后者回忆起一个叫做Spring Boot的东西,这将帮助您避免浪费时间解决小项目设置的细微差别并快速切换编写应用程序代码。
因此,我们亲爱的阿尔弗雷德(Alfred)开始使用Spring Boot快速创建正义联盟会员管理系统。 由于Batman直接与REST API配合使用,因此至少是后端部分。
有许多方便的方法来配置Spring Boot应用程序。 在本文中,我们将重点介绍下载软件包(Spring CLI)并在Ubuntu上从头进行设置的传统方法。 Spring还支持使用其
工具在线打包项目。 在
此处下载最新的稳定版本。 在本文中,我正在使用1.3.0.M1版本。
解压缩下载的归档文件后,对于初学者,请在配置文件中配置以下参数:
SPRING_BOOT_HOME=<extracted path>/spring-1.3.0.M1 PATH=$SPRING_BOOT_HOME/bin:$PATH
然后将以下内容添加到bashrc文件中:
<extracted-path>/spring-1.3.0.M1/shell-completion/bash/spring
使用spring-cli创建Spring Boot应用程序时,这会将自动完成功能添加到命令行中。 请记住,要确认更改,您需要“提供”配置文件和“ bashrc”文件。
本文使用以下技术堆栈:
我们首先通过运行以下命令来创建应用程序项目模板。 请注意,可以从我的GitHub存储库中下载示例项目。
spring init -dweb,data-mongodb,flapdoodle-mongo --groupId com.justiceleague --artifactId justiceleaguemodule --build maven justiceleaguesystem
这将使用Spring MVC和带有集成MongoDB的Spring Data生成一个maven项目。
默认情况下,spring-cli创建一个名为“ Demo”的项目。 因此,我们需要重命名相应的生成的应用程序类。 如果您使用了上述我的GitHub存储库中的源,则可以跳过此步骤。
使用Spring Boot,运行应用程序就像运行项目创建的JAR文件一样简单。 它只是调用由@SpringBootApplication注释的应用程序类来加载Spring。 让我们看看它的外观:
package com.justiceleague.justiceleaguemodule; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class JusticeLeagueManagementApplication { public static void main(String[] args) { SpringApplication.run(JusticeLeagueManagementApplication.class, args); } }
然后,我们进入域类,其中Spring Data和MongoDB一起用于确定数据级别。 域类如下:
package com.justiceleague.justiceleaguemodule.domain; import org.bson.types.ObjectId; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.mapping.Document; @Document(collection = "justiceLeagueMembers") public class JusticeLeagueMemberDetail { @Id private ObjectId id; @Indexed private String name; private String superPower; private String location; public JusticeLeagueMemberDetail(String name, String superPower, String location) { this.name = name; this.superPower = superPower; this.location = location; } public String getId() { return id.toString(); } public void setId(String id) { this.id = new ObjectId(id); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSuperPower() { return superPower; } public void setSuperPower(String superPower) { this.superPower = superPower; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } }
Spring Data非常直观,特别是如果您有使用JPA / Hibernate的经验。 注释非常相似。 唯一的新事物是注释。
@Document
它表示Mongo数据库中集合的名称。 还有一个为超级英雄名称定义的索引,因为许多查询将与按名称进行的搜索有关。
Spring Data引入了简单存储库定义的功能,开箱即用,支持常规CRUD操作和某些读取操作。 因此,在我们的应用程序中,我们使用Spring Data存储库的功能以及存储库类,如下所示:
package com.justiceleague.justiceleaguemodule.dao; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.data.mongodb.repository.Query; import com.justiceleague.justiceleaguemodule.domain.JusticeLeagueMemberDetail; public interface JusticeLeagueRepository extends MongoRepository < JusticeLeagueMemberDetail, String > { @Query("{ 'name' : {$regex: ?0, $options: 'i' }}") JusticeLeagueMemberDetail findBySuperHeroName(final String superHeroName); }
标准的保存操作通过代理内置在Spring的运行时中,因此您只需要在存储库中定义域类。
如您所见,仅定义了一种方法。 借助
@Query
批注
@Query
我们正在寻找使用正则表达式的超级英雄。 “ i”选项意味着在MongoDB中尝试查找匹配项时忽略大小写。
然后,我们将通过服务级别实施存储正义联盟新成员的逻辑。

package com.justiceleague.justiceleaguemodule.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.justiceleague.justiceleaguemodule.constants.MessageConstants.ErrorMessages; import com.justiceleague.justiceleaguemodule.dao.JusticeLeagueRepository; import com.justiceleague.justiceleaguemodule.domain.JusticeLeagueMemberDetail; import com.justiceleague.justiceleaguemodule.exception.JusticeLeagueManagementException; import com.justiceleague.justiceleaguemodule.service.JusticeLeagueMemberService; import com.justiceleague.justiceleaguemodule.web.dto.JusticeLeagueMemberDTO; import com.justiceleague.justiceleaguemodule.web.transformer.DTOToDomainTransformer; @Service public class JusticeLeagueMemberServiceImpl implements JusticeLeagueMemberService { @Autowired private JusticeLeagueRepository justiceLeagueRepo; public void addMember(JusticeLeagueMemberDTO justiceLeagueMember) { JusticeLeagueMemberDetail dbMember = justiceLeagueRepo.findBySuperHeroName(justiceLeagueMember.getName()); if (dbMember != null) { throw new JusticeLeagueManagementException(ErrorMessages.MEMBER_ALREDY_EXISTS); } JusticeLeagueMemberDetail memberToPersist = DTOToDomainTransformer.transform(justiceLeagueMember); justiceLeagueRepo.insert(memberToPersist); } }
同样,这很简单-如果参与者已经存在,那么我们会收到一个错误消息。 否则,添加参与者。 请注意,这使用了我们先前定义的插入存储库的已实现Spring Data方法。
最后,Alfred准备展示他使用Spring REST通过REST API开发的新功能,以便Batman开始通过HTTP发送详细信息-他一直在前进:
package com.justiceleague.justiceleaguemodule.web.rest.controller; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import com.justiceleague.justiceleaguemodule.constants.MessageConstants; import com.justiceleague.justiceleaguemodule.service.JusticeLeagueMemberService; import com.justiceleague.justiceleaguemodule.web.dto.JusticeLeagueMemberDTO; import com.justiceleague.justiceleaguemodule.web.dto.ResponseDTO; @RestController @RequestMapping("/justiceleague") public class JusticeLeagueManagementController { @Autowired private JusticeLeagueMemberService memberService; @ResponseBody @ResponseStatus(value = HttpStatus.CREATED) @RequestMapping(method = RequestMethod.POST, path = "/addMember", produces = { MediaType.APPLICATION_JSON_VALUE }, consumes = { MediaType.APPLICATION_JSON_VALUE }) public ResponseDTO addJusticeLeagueMember(@Valid @RequestBody JusticeLeagueMemberDTO justiceLeagueMember) { ResponseDTO responseDTO = new ResponseDTO(ResponseDTO.Status.SUCCESS, MessageConstants.MEMBER_ADDED_SUCCESSFULLY); try { memberService.addMember(justiceLeagueMember); } catch (Exception e) { responseDTO.setStatus(ResponseDTO.Status.FAIL); responseDTO.setMessage(e.getMessage()); } return responseDTO; } }
蝙蝠侠还不够,因此我们以JSON有效负载的形式提供功能,尽管Alfred会过时并且会更喜欢XML。
我们的老朋友阿尔弗雷德(Alfred)是TDD(测试驱动开发,翻译为“通过测试开发”)的忠实拥护者,因此他想测试功能。 因此,我们着眼于阿尔弗雷德(Alfred)编写的集成测试,以确保正义联盟(Justice League)管理系统的初始版本正确且可预测。 请注意,此处仅显示REST API测试。 Alfred已达到更大的数量,可以在
GitHub存储库中找到。
package com.justiceleague.justiceleaguemodule.test.util; import java.io.IOException; import java.net.UnknownHostException; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; 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.data.mongodb.core.MongoTemplate; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import com.fasterxml.jackson.databind.ObjectMapper; import com.justiceleague.justiceleaguemodule.domain.JusticeLeagueMemberDetail; import de.flapdoodle.embed.mongo.MongodExecutable; import de.flapdoodle.embed.mongo.MongodStarter; import de.flapdoodle.embed.mongo.config.IMongodConfig; import de.flapdoodle.embed.mongo.config.MongodConfigBuilder; import de.flapdoodle.embed.mongo.config.Net; import de.flapdoodle.embed.mongo.distribution.Version; @RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc public abstract class BaseIntegrationTest { @Autowired protected MockMvc mockMvc; protected ObjectMapper mapper; private static MongodExecutable mongodExecutable; @Autowired protected MongoTemplate mongoTemplate; @Before public void setUp() { mapper = new ObjectMapper(); } @After public void after() { mongoTemplate.dropCollection(JusticeLeagueMemberDetail.class); } @BeforeClass public static void beforeClass() throws UnknownHostException, IOException { MongodStarter starter = MongodStarter.getDefaultInstance(); IMongodConfig mongoConfig = new MongodConfigBuilder().version(Version.Main.PRODUCTION) .net(new Net(27017, false)).build(); mongodExecutable = starter.prepare(mongoConfig); try { mongodExecutable.start(); } catch (Exception e) { closeMongoExecutable(); } } @AfterClass public static void afterClass() { closeMongoExecutable(); } private static void closeMongoExecutable() { if (mongodExecutable != null) { mongodExecutable.stop(); } } }
package com.justiceleague.justiceleaguemodule.web.rest.controller; import org.hamcrest.beans.SamePropertyValuesAs; import org.junit.Assert; import org.junit.Test; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import com.justiceleague.justiceleaguemodule.constants.MessageConstants; import com.justiceleague.justiceleaguemodule.constants.MessageConstants.ErrorMessages; import com.justiceleague.justiceleaguemodule.domain.JusticeLeagueMemberDetail; import com.justiceleague.justiceleaguemodule.test.util.BaseIntegrationTest; import com.justiceleague.justiceleaguemodule.web.dto.JusticeLeagueMemberDTO; import com.justiceleague.justiceleaguemodule.web.dto.ResponseDTO; import com.justiceleague.justiceleaguemodule.web.dto.ResponseDTO.Status; public class JusticeLeagueManagementControllerTest extends BaseIntegrationTest { @Test public void testAddJusticeLeagueMember() throws Exception { JusticeLeagueMemberDTO flash = new JusticeLeagueMemberDTO("Barry Allen", "super speed", "Central City"); String jsonContent = mapper.writeValueAsString(flash); String response = mockMvc .perform(MockMvcRequestBuilders.post("/justiceleague/addMember") .accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON).content(jsonContent)) .andExpect(MockMvcResultMatchers.status().isCreated()).andReturn().getResponse().getContentAsString(); ResponseDTO expected = new ResponseDTO(Status.SUCCESS, MessageConstants.MEMBER_ADDED_SUCCESSFULLY); ResponseDTO receivedResponse = mapper.readValue(response, ResponseDTO.class); Assert.assertThat(receivedResponse, SamePropertyValuesAs.samePropertyValuesAs(expected)); } @Test public void testAddJusticeLeagueMemberWhenMemberAlreadyExists() throws Exception { JusticeLeagueMemberDetail flashDetail = new JusticeLeagueMemberDetail("Barry Allen", "super speed","Central City"); mongoTemplate.save(flashDetail); JusticeLeagueMemberDTO flash = new JusticeLeagueMemberDTO("Barry Allen", "super speed", "Central City"); String jsonContent = mapper.writeValueAsString(flash); String response = mockMvc .perform(MockMvcRequestBuilders.post("/justiceleague/addMember"). accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON).content(jsonContent)) .andExpect(MockMvcResultMatchers.status().isCreated()).andReturn().getResponse() .getContentAsString(); ResponseDTO expected = new ResponseDTO(Status.FAIL, ErrorMessages.MEMBER_ALREDY_EXISTS); ResponseDTO receivedResponse = mapper.readValue(response, ResponseDTO.class); Assert.assertThat(receivedResponse, SamePropertyValuesAs.samePropertyValuesAs(expected)); } @Test public void testAddJusticeLeagueMemberWhenNameNotPassedIn() throws Exception {
仅此而已。 在Spring Boot的帮助下,Alfred能够使用REST API快速创建功能最弱的Justice League管理系统。 随着时间的流逝,我们将扩展此应用程序的功能,并了解Alfred如何找到一种通过Docker将应用程序部署到Kubernetes管理的Amazon AWS实例的方法。 激动人心的时刻在等待着我们,因此联系起来!
传统上,我们会等待您的评论,我们邀请您参加
公开网络研讨会 ,该
研讨会将于2月6日由物理和数学科学候选人
Yuri Dvorzhetsky举行 。