Halo semuanya. Kami segera mengucapkan selamat kepada siswa pada liburan profesional mereka dan untuk menginformasikan bahwa pada bulan Februari kami akan memulai kursus
"Pengembang Kerangka Kerja Musim Semi" ! Ini akan menjadi subjek publikasi hari ini.
Justice League dalam bahaya, dan hanya Alfred yang bisa menyelamatkan semua orang - dengan sistem manajemen baru dengan Spring Boot, Spring Data dan MongoDB.
Bagi Justice League, masa-masa kelam telah tiba ketika Darkside yang mengagumkan memutuskan untuk memperbudak manusia. Batman dan Wonder Woman mulai mencari anggota Liga, dan hanya ada satu poin penting yang hilang - sistem manajemen yang tepat untuk anggota Liga Keadilan.

Tidak ada cukup waktu untuk membuat proyek besar dari awal, jadi Batman mentransfer tugas sulit ini kepada Alfred tercinta (lagipula, Robin terlalu tidak terduga), yang mengingat sesuatu yang disebut Spring Boot, yang akan membantu Anda untuk tidak membuang waktu menyelesaikan nuansa pengaturan proyek kecil dan dengan cepat beralih untuk menulis kode aplikasi.
Jadi Alfred kita mulai menggunakan Spring Boot untuk dengan cepat membuat sistem manajemen keanggotaan Justice League. Minimal, bagian belakangnya, karena Batman bekerja langsung dengan REST API.
Ada banyak cara mudah untuk mengkonfigurasi aplikasi Boot Spring. Pada artikel ini, kita akan fokus pada metode tradisional mengunduh paket (Spring CLI) dan mengaturnya dari awal di Ubuntu. Spring juga mendukung pengemasan proyek secara online dengan
alat mereka. Unduh versi stabil terbaru di
sini . Pada artikel ini, saya menggunakan versi 1.3.0.M1.
Setelah membongkar arsip yang diunduh, sebagai permulaan, konfigurasikan parameter berikut di profil:
SPRING_BOOT_HOME=<extracted path>/spring-1.3.0.M1 PATH=$SPRING_BOOT_HOME/bin:$PATH
Kemudian tambahkan berikut ini ke file bashrc:
<extracted-path>/spring-1.3.0.M1/shell-completion/bash/spring
Ini akan menambahkan penyelesaian otomatis ke baris perintah ketika bekerja dengan spring-cli untuk membuat aplikasi Spring Boot. Ingatlah bahwa untuk mengonfirmasi perubahan, Anda perlu "mencari" profil dan file "bashrc".
Artikel ini menggunakan tumpukan teknologi berikut:
- SISA Musim Semi
- Data Musim Semi
- MongoDB.
Kami mulai dengan membuat templat proyek aplikasi dengan menjalankan perintah berikut. Harap dicatat bahwa proyek sampel dapat diunduh dari repositori GitHub saya di
sini .
spring init -dweb,data-mongodb,flapdoodle-mongo --groupId com.justiceleague --artifactId justiceleaguemodule --build maven justiceleaguesystem
Ini akan menghasilkan proyek pakar dengan Spring MVC dan Spring Data dengan MongoDB terintegrasi.
Secara default, spring-cli membuat proyek yang disebut "Demo". Oleh karena itu, kita perlu mengganti nama kelas aplikasi yang dihasilkan. Jika Anda menggunakan sumber dari repositori GitHub saya yang disebutkan di atas, maka Anda dapat melewati langkah ini.
Menggunakan Spring Boot, menjalankan aplikasi semudah menjalankan file JAR yang dibuat oleh proyek. Yang hanya memanggil kelas aplikasi yang dijelaskan oleh @SpringBootApplication untuk memuat Spring. Mari kita lihat tampilannya:
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); } }
Kemudian kita beralih ke kelas domain, di mana Spring Data bersama dengan MongoDB digunakan untuk menentukan tingkat data. Kelas domain adalah sebagai berikut:
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 intuitif, terutama jika Anda memiliki pengalaman dengan JPA / Hibernate. Anotasi sangat mirip. Satu-satunya hal baru adalah penjelasan.
@Document
yang menunjukkan nama koleksi di database Mongo. Ada juga indeks yang ditentukan untuk nama pahlawan super, karena banyak pertanyaan akan berhubungan dengan pencarian berdasarkan nama.
Spring Data memperkenalkan fungsionalitas definisi repositori sederhana, di luar kotak yang mendukung operasi CRUD reguler dan beberapa operasi baca. Dengan demikian, dalam aplikasi kami, kami menggunakan kemampuan repositori Data Spring, serta kelas repositori sebagai berikut:
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); }
Operasi penyimpanan standar dibangun ke runtime Spring melalui proxy, jadi Anda hanya perlu mendefinisikan kelas domain di repositori.
Seperti yang Anda lihat, hanya satu metode yang didefinisikan. Dengan penjelasan
@Query
kami mencari seorang pahlawan super menggunakan ekspresi reguler. Opsi "i" berarti mengabaikan kasus ketika mencoba menemukan kecocokan di MongoDB.
Kemudian, kami melanjutkan ke implementasi logika penyimpanan anggota baru Justice League melalui tingkat layanan.

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); } }
Sekali lagi, ini cukup sederhana - jika peserta sudah ada, maka kami akan membuat kesalahan. Jika tidak, tambahkan peserta. Perhatikan bahwa ini menggunakan metode Data Spring yang sudah diterapkan dari repositori insert, yang telah kami definisikan sebelumnya.
Akhirnya, Alfred siap untuk menunjukkan fungsionalitas baru yang ia kembangkan melalui REST API menggunakan Spring REST, sehingga Batman mulai mengirim detail melalui HTTP - ia terus bergerak:
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; } }
Batman tidak cukup, jadi kami menyediakan fungsionalitas dalam bentuk muatan JSON, meskipun Alfred akan kuno dan lebih suka XML.
Teman lama kami, Alfred, adalah antek TDD (test-driven development, diterjemahkan "development through testing"), jadi ia ingin menguji fungsionalitasnya. Jadi kami melihat tes integrasi yang ditulis oleh Alfred untuk memastikan bahwa versi awal sistem manajemen Liga Keadilan sudah benar dan dapat diprediksi. Harap perhatikan bahwa di sini kami hanya menampilkan tes REST API. Alfred telah merangkul volume yang lebih besar, yang dapat ditemukan di repositori
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 {
Itu mungkin saja. Dengan bantuan Spring Boot, Alfred dapat dengan cepat membuat sistem manajemen Justice League yang berfungsi minimal dengan REST API. Seiring waktu, kami akan memperluas fungsionalitas aplikasi ini dan melihat bagaimana Alfred menemukan pendekatan untuk menyebarkan aplikasi melalui Docker ke instance Amazon AWS yang dikelola oleh Kubernetes. Waktu yang menyenangkan menunggu kami, jadi terhubunglah!
Secara tradisional, kami menunggu komentar Anda dan diundang ke
webinar terbuka , yang akan diadakan pada 6 Februari oleh kandidat ilmu fisika dan matematika -
Yuri Dvorzhetsky .