算法正义
正义联盟(Justice League)进入了黑暗时代,强大的Darkseid征服了人类。 蝙蝠侠在《神力女超人》的帮助下,努力使联盟与一个关键方面失联。 适当的正义联盟成员管理系统。 由于时间不在他们身边,他们不想经历繁琐的过程,从头开始用他们需要的所有东西来建立项目。 蝙蝠侠将艰巨的任务交给了他心爱的值得信任的阿尔弗雷德·阿尔弗雷德(由于罗宾是如此不可预测),他告诉蝙蝠侠他回忆起遇到了一个叫做Spring Boot的东西,它可以帮助您设置所需的一切,以便您可以编写代码您的应用程序,而不会因设置项目配置的细微差别而陷入困境。 于是他进入了。 让我们与心爱的阿尔弗雷德(Alfred)谈谈,他将立即利用Spring Boot建立正义联盟成员管理系统。 自从蝙蝠侠喜欢直接使用REST API以来,至少现在是后端部分。
有许多方便的方法来设置Spring Boot应用程序。 在本文中,我们将重点介绍下载软件包(Spring CLI)并在Ubuntu上从头开始进行设置的传统方式。 Spring还支持通过其工具在线打包项目。 您可以从此处下载最新的稳定版本。 对于本文,我使用的是1.3.0.M1版本。
解压缩下载的存档后,首先,在配置文件中设置以下参数;
SPRING_BOOT_HOME=<extracted path>/spring-1.3.0.M1PATH=$SPRING_BOOT_HOME/bin:$PATH
然后在您的“ bashrc”文件中包括以下内容;
. <extracted-path>/spring-1.3.0.M1/shell-completion/bash/spring
最后执行的操作是,当您处理spring-cli以创建自己的spring boot应用程序时,它将使您在命令行上自动完成。 请记住同时“提供”配置文件和“ bashrc”文件,以使更改生效。
本文使用的技术栈如下:
- SpringREST
- Spring数据
- MongoDB
因此,让我们通过发出以下命令开始为应用程序创建模板项目。 请注意,可以从找到的GitHub存储库中下载示例项目
在这里 ;
spring init -dweb,data-mongodb,flapdoodle-mongo --groupId com.justiceleague --artifactId justiceleaguemodule --build maven justiceleaguesystem
这将使用Spring MVC和Spring Data以及嵌入式MongoDB生成一个maven项目。
默认情况下,spring-cli创建一个名称设置为“ Demo”的项目。 因此,我们将需要重命名生成的各个应用程序类。 如果您从上述我的GitHub存储库中签出了源代码,那么将完成此操作。
使用Spring boot,运行该应用程序就像运行该项目创建的jar文件一样简单,该jar文件实际上会调用该应用程序
用@SpringBootApplication注释的类可引导Spring。 让我们看看它是什么样子;
package com.justiceleague.justiceleaguemodule;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** The main spring boot application which will start up a web container and wire* up all the required beans.* * @author dinuka**/
@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;/*** This class holds the details that will be stored about the justice league* members on MongoDB.* * @author dinuka**/
@Document(collection = "justiceLeagueMembers")
public class JusticeLeagueMemberDetail {@Idprivate ObjectId id;@Indexedprivate 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数据时,它非常直观,特别是如果您来自JPA / Hibernate背景。 注释非常相似。 唯一的新东西是@Document批注,它表示我们mongo数据库中集合的名称。 我们还会在超级英雄的名称上定义一个索引,因为更多查询将围绕按名称搜索。
Spring-data附带了轻松定义存储库的功能,这些存储库支持通常的CRUD操作和一些读取操作,而无需直接编写即可。 因此,我们在应用程序中也利用了Spring数据存储库的功能,存储库类如下:
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> {/*** This method will retrieve the justice league member details pertaining to* the name passed in.* * @param superHeroName* the name of the justice league member to search and retrieve.* @return an instance of {@link JusticeLeagueMemberDetail} with the member* details.*/@Query("{ 'name' : {$regex: ?0, $options: 'i' }}")JusticeLeagueMemberDetail findBySuperHeroName(final String superHeroName);
}
常规的保存操作由Spring在运行时通过使用代理实现,我们只需要在存储库中定义域类即可。
如您所见,我们仅定义了一种方法。 借助@Query批注,我们试图与正则表达式用户一起寻找超级英雄。 选项“ i”表示尝试在mongo db中查找匹配项时,我们应忽略大小写。
接下来,我们继续执行我们的逻辑以通过我们的服务层存储新的正义联盟成员。
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;/*** This service class implements the {@link JusticeLeagueMemberService} to* provide the functionality required for the justice league system.* * @author dinuka**/
@Service
public class JusticeLeagueMemberServiceImpl implements JusticeLeagueMemberService {@Autowiredprivate JusticeLeagueRepository justiceLeagueRepo;/*** {@inheritDoc}*/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数据存储库的insert方法。
最终,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;/*** This class exposes the REST API for the system.* * @author dinuka**/
@RestController
@RequestMapping("/justiceleague")
public class JusticeLeagueManagementController {@Autowiredprivate JusticeLeagueMemberService memberService;/*** This method will be used to add justice league members to the system.* * @param justiceLeagueMember* the justice league member to add.* @return an instance of {@link ResponseDTO} which will notify whether* adding the member was successful.*/@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,但Batman却无法获得足够的功能。
老家伙Alfred仍然想测试一下他的功能,因为TDD只是他的风格。 因此,最后我们看一下Alfred编写的集成测试,以确保正义联盟管理系统的初始版本能够按预期工作。 请注意,尽管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;/*** This class will have functionality required when running integration tests so* that invidivual classes do not need to implement the same functionality.* * @author dinuka**/
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public abstract class BaseIntegrationTest {@Autowiredprotected MockMvc mockMvc;protected ObjectMapper mapper;private static MongodExecutable mongodExecutable;@Autowiredprotected MongoTemplate mongoTemplate;@Beforepublic void setUp() {mapper = new ObjectMapper();}@Afterpublic void after() {mongoTemplate.dropCollection(JusticeLeagueMemberDetail.class);}/*** Here we are setting up an embedded mongodb instance to run with our* integration tests.* * @throws UnknownHostException* @throws IOException*/@BeforeClasspublic 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();}}@AfterClasspublic 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;/*** This class will test out the REST controller layer implemented by* {@link JusticeLeagueManagementController}* * @author dinuka**/
public class JusticeLeagueManagementControllerTest extends BaseIntegrationTest {/*** This method will test if the justice league member is added successfully* when valid details are passed in.* * @throws Exception*/@Testpublic 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));}/*** This method will test if an appropriate failure response is given when* the member being added already exists within the system.* * @throws Exception*/@Testpublic 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));}/*** This method will test if a valid client error is given if the data* required are not passed within the JSON request payload which in this* case is the super hero name.* * @throws Exception*/@Testpublic void testAddJusticeLeagueMemberWhenNameNotPassedIn() throws Exception {// The super hero name is passed in as null here to see whether the// validation error handling kicks in.JusticeLeagueMemberDTO flash = new JusticeLeagueMemberDTO(null, "super speed", "Central City");String jsonContent = mapper.writeValueAsString(flash);mockMvc.perform(MockMvcRequestBuilders.post("/justiceleague/addMember").accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON).content(jsonContent)).andExpect(MockMvcResultMatchers.status().is4xxClientError());}}
就是这样。 借助Spring Boot的强大功能,Alfred能够立即获得带有REST API的最低限度的正义联盟管理系统。 我们将在接下来的时间基于该应用程序构建,并查看Alfred如何提出将这个应用程序通过docker部署到由Kubernetes管理的Amazon AWS实例上。 激动人心的时代即将来临。
翻译自: https://www.javacodegeeks.com/2017/07/spring-boot-justice-league.html
算法正义