Panduan Penukaran Jenis Musim Semi

1. Pengenalan

Dalam artikel ini, kita akan melihat penukaran jenis Spring.

Spring menyediakan pelbagai penukar luar kotak untuk jenis terbina dalam; ini bermaksud menukar ke / dari jenis asas seperti String, Integer, Boolean dan sebilangan jenis lain.

Selain itu, Spring juga menyediakan SPI penukaran jenis pepejal untuk mengembangkan penukar khas kami.

2. Penukar terbina dalam s

Kami akan mulakan dengan penukar yang tersedia di musim bunga; mari kita lihat penukaran String to Integer :

@Autowired ConversionService conversionService; @Test public void whenConvertStringToIntegerUsingDefaultConverter_thenSuccess() { assertThat( conversionService.convert("25", Integer.class)).isEqualTo(25); }

Satu-satunya perkara yang perlu kita lakukan di sini adalah untuk autowire yang ConversionService disediakan oleh Spring dan memanggil convert () kaedah. Argumen pertama adalah nilai yang ingin kita tukar dan argumen kedua adalah jenis sasaran yang ingin kita tukar.

Selain daripada contoh String to Integer ini , terdapat banyak pelbagai kombinasi lain yang tersedia untuk kita.

3. Membuat Penukar Tersuai

Mari kita lihat contoh menukar perwakilan String Karyawan ke contoh Pekerja .

Inilah kelas Pekerja :

public class Employee { private long id; private double salary; // standard constructors, getters, setters }

The String akan menjadi pasangan yang dipisahkan koma yang mewakili id dan gaji. Contohnya, "1,50000.00".

Untuk membuat Converter khusus kami , kami perlu menerapkan antara muka Converter dan menerapkan kaedah convert () :

public class StringToEmployeeConverter implements Converter { @Override public Employee convert(String from) { String[] data = from.split(","); return new Employee( Long.parseLong(data[0]), Double.parseDouble(data[1])); } }

Kami belum selesai. Kita juga perlu memberitahu Spring mengenai penukar baru ini dengan menambahkan StringToEm EmployeeConverter ke FormatterRegistry . Ini dapat dilakukan dengan menerapkan kaedah WebMvcConfigurer dan mengesampingkan kaedah addFormatters () :

@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new StringToEmployeeConverter()); } }

Dan itu sahaja. Converter baru kami kini tersedia untuk ConversionService dan kami dapat menggunakannya dengan cara yang sama seperti Converter bawaan lain :

@Test public void whenConvertStringToEmployee_thenSuccess() { Employee employee = conversionService .convert("1,50000.00", Employee.class); Employee actualEmployee = new Employee(1, 50000.00); assertThat(conversionService.convert("1,50000.00", Employee.class)) .isEqualToComparingFieldByField(actualEmployee); }

3.1. Penukaran Tersirat

Di luar penukaran eksplisit ini menggunakan ConversionService , Spring juga mampu menukar nilai secara tersirat secara langsung dalam kaedah Pengawal untuk semua penukar berdaftar:

@RestController public class StringToEmployeeConverterController { @GetMapping("/string-to-employee") public ResponseEntity getStringToEmployee( @RequestParam("employee") Employee employee) { return ResponseEntity.ok(employee); } }

Ini adalah cara yang lebih semula jadi untuk menggunakan Converter s. Mari tambahkan ujian untuk melihatnya beraksi:

@Test public void getStringToEmployeeTest() throws Exception { mockMvc.perform(get("/string-to-employee?employee=1,2000")) .andDo(print()) .andExpect(jsonPath("$.id", is(1))) .andExpect(jsonPath("$.salary", is(2000.0))) }

Seperti yang anda lihat, ujian akan mencetak semua butiran permintaan dan juga respons. Berikut adalah objek Kakitangan dalam format JSON yang dikembalikan sebagai sebahagian daripada tindak balas:

{"id":1,"salary":2000.0}

4. Membuat ConverterFactory

Anda juga boleh membuat ConverterFactory yang membuat Converter sesuai permintaan. Ini sangat membantu dalam mewujudkan Converter s untuk Enums .

Mari kita lihat Enum yang sangat sederhana:

public enum Modes { ALPHA, BETA; }

Seterusnya, mari buat StringToEnumConverterFactory yang boleh menghasilkan Converter s untuk menukar String ke Enum mana pun :

@Component public class StringToEnumConverterFactory implements ConverterFactory { private static class StringToEnumConverter implements Converter { private Class enumType; public StringToEnumConverter(Class enumType) { this.enumType = enumType; } public T convert(String source) { return (T) Enum.valueOf(this.enumType, source.trim()); } } @Override public  Converter getConverter( Class targetType) { return new StringToEnumConverter(targetType); } }

Seperti yang kita lihat, kelas kilang secara dalaman menggunakan pelaksanaan antara muka Converter .

Satu perkara yang perlu diperhatikan di sini adalah bahawa walaupun kita akan menggunakan Modes Enum untuk menunjukkan penggunaannya, kita belum menyebut Enum di mana pun di StringToEnumConverterFactory . Kelas kilang kami cukup generik untuk menghasilkan Converter sesuai permintaan untuk sebarang jenis Enum .

Langkah seterusnya adalah mendaftarkan kelas kilang ini semasa kami mendaftarkan Penukar kami dalam contoh sebelumnya:

@Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new StringToEmployeeConverter()); registry.addConverterFactory(new StringToEnumConverterFactory()); }

Sekarang ConversionService siap menukar String s ke Enum s:

@Test public void whenConvertStringToEnum_thenSuccess() { assertThat(conversionService.convert("ALPHA", Modes.class)) .isEqualTo(Modes.ALPHA); }

5. Membuat GenericConverter

A GenericConverter memberikan kita lebih banyak fleksibiliti untuk membuat Wang untuk kegunaan yang lebih generik pada kos kehilangan beberapa keselamatan jenis.

Mari kita pertimbangkan contoh menukar nilai Integer , Double , atau String ke nilai BigDecimal. Kami tidak perlu menulis tiga Converter untuk ini. GenericConverter sederhana dapat memenuhi tujuan tersebut.

Langkah pertama adalah memberitahu Spring jenis penukaran yang disokong. Kami melakukan ini dengan mewujudkan satu set daripada ConvertiblePair :

public class GenericBigDecimalConverter implements GenericConverter { @Override public Set getConvertibleTypes () { ConvertiblePair[] pairs = new ConvertiblePair[] { new ConvertiblePair(Number.class, BigDecimal.class), new ConvertiblePair(String.class, BigDecimal.class)}; return ImmutableSet.copyOf(pairs); } }

Langkah seterusnya adalah mengatasi kaedah convert () di kelas yang sama:

@Override public Object convert (Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { if (sourceType.getType() == BigDecimal.class) { return source; } if(sourceType.getType() == String.class) { String number = (String) source; return new BigDecimal(number); } else { Number number = (Number) source; BigDecimal converted = new BigDecimal(number.doubleValue()); return converted.setScale(2, BigDecimal.ROUND_HALF_EVEN); } }

Kaedah tukar () semudah yang boleh. Walau bagaimanapun, TypeDescriptor memberikan kita fleksibiliti yang besar dalam mendapatkan perincian mengenai sumber dan jenis sasaran.

Seperti yang sudah anda duga, langkah seterusnya adalah mendaftarkan Penukar ini :

@Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new StringToEmployeeConverter()); registry.addConverterFactory(new StringToEnumConverterFactory()); registry.addConverter(new GenericBigDecimalConverter()); }

Menggunakan Penukar ini serupa dengan contoh lain yang telah kita lihat:

@Test public void whenConvertingToBigDecimalUsingGenericConverter_thenSuccess() { assertThat(conversionService .convert(Integer.valueOf(11), BigDecimal.class)) .isEqualTo(BigDecimal.valueOf(11.00) .setScale(2, BigDecimal.ROUND_HALF_EVEN)); assertThat(conversionService .convert(Double.valueOf(25.23), BigDecimal.class)) .isEqualByComparingTo(BigDecimal.valueOf(Double.valueOf(25.23))); assertThat(conversionService.convert("2.32", BigDecimal.class)) .isEqualTo(BigDecimal.valueOf(2.32)); }

6. Kesimpulannya

Dalam tutorial ini, kami telah melihat bagaimana menggunakan dan memperluas sistem penukaran jenis Spring dengan pelbagai contoh.

Seperti biasa, kod sumber penuh untuk artikel ini boleh didapati di GitHub.