Spring @RestController μλ΅ μ, μ μ λμ§ μμ κ°λ κ°μ΄ μλ΅λλ μ΄μ
@Getter
@Setter
public class UserDomain {
private String name;
private int age;
public boolean isTwenties() {
if (this.age >= 20 && this.age < 30){
return true;
}
return false;
}
}
- μμ κ°μ΄, λλ©μΈ κ°μ²΄ μμ λΉμ¦λμ€ λ‘μ§μ΄ ν¬ν¨λ λ©μλκ° μ‘΄μ¬νλ€κ³ μμν΄λ³΄μ.
- isTwenties() λ νμ¬ Userμ λμ΄λ₯Ό νλ¨νμ¬ 20λμΈμ§ μλμ§λ₯Ό μλ €μ£Όλ λ©μλμ΄λ€.
@RestController
public class UserController {
@GetMapping("/user/{name}")
public UserDomain retrieveUserByName(String name){
UserDomain user = new UserDomain():
user.setName("test");
user.setAge(10);
return user;
}
}
λ§μ½, RestControllerμμ UserDomainμ μλ΅ κ°μ²΄λ‘ μ¬μ©νκ² λλ€λ©΄ HTTP μλ΅μΌλ‘ μ΄λ€ κ°μ΄ μλ΅λ κΉ?
λλ μ²μμ μ΄μ κ°μ μλ΅μ κΈ°λνλ€.
{
"name": "test",
"age" : 10
}
νμ§λ§, μ€μ λ‘ μλ΅ λ κ°μ κ·Έλ μ§ μμλ€. π§
{
"name": "test",
"age" : 10,
"Twenties" : false
}
μ μ΄λ° κ²°κ³Όκ° λμ€κ² λμμκΉ? μ΄μ λ₯Ό μκΈ° μν΄μ @ResponseBodyμ HttpMessageConverterμ λν μ ν μ§μμ΄ μ΄μ§ νμνλ€.
@ResponseBody
Springμ HTTP μμ²μ λ°μμ λ κ·Έ μλ΅μΌλ‘ (1) μ μ 리μμ€ (2) λ·° ν νλ¦Ώμ μλ΅νκ±°λ νΉμ (3) HTTP Body κ°μ μλ΅ν μ μλ€.
μ΄λ (3) HTTP Body κ°μ μλ΅νλ €λ©΄, @ResponseBody μ΄λ Έν μ΄μ μ λ©μλ μλ¨μ λΆμ¬μΌ νλ€.
κ·Έλ¦¬κ³ , ν΄λμ€ μλ¨μ @RestController μ λ Έν μ΄μ μ μ¬μ©νλ©΄ ν΄λΉ 컨νΈλ‘€λ¬μ λͺ¨λ λ©μλμ @ResponseBodyκ° μ μ©λλ ν¨κ³Όκ° μλ€
(@Controllerλ method return typeμ΄ Stringμ΄λ©΄ λ·° μ΄λ¦μΌλ‘ μΈμν΄, λ·°λ₯Ό μ°Ύκ³ λ·°λ₯Ό λλλ§ νλ€. @RestController λ λ°ν κ°μΌλ‘ λ·°λ₯Ό μ°Ύλ κ²μ΄ μλλΌ, HTTP λ©μμ§ λ°λμ λ°λ‘ μ λ ₯νλ€.)
HttpMessageConverter
Springμ μλ΅κ°μ μμ±ν λ, ReturnValueHandlerκ° RequestMappingμΌλ‘ μλ³λ λ©μλμ μλ΅ νμ μ νμΈνκ³ , ν΄λΉ μλ΅ νμ μ μ§λ ¬ν ν μ μλ HttpMessageConverterλ₯Ό μ°Ύμ μ€ννλ€.
-> μμ κ°μ μν©μΌ λλ MappingJackson2HttpMessageConverter κ° μ€ν λλ€.
μ무νΌ, μμλ‘ λ UserControllerκ° @RestControllerμ΄κ³ λ©μλμ μλ΅κ°μ΄ κ°μ²΄μ΄κΈ° λλ¬Έμ, MappingJackson2HttpMessageConverter κ° UserDomain κ°μ²΄λ₯Ό μ§λ ¬ν νκ² λλ€.
μ΄λ λ¬Έμ λ, νλ κΈ°λ°μΌλ‘ κ°μ μ§λ ¬ν νλκ² μλλΌ get ν€μλλ‘ μμνλ λ©μλλ₯Ό 'νλ'λΌκ³ μΈμνκ³ μ§λ ¬ν νκ² λλ€λ μ μ΄λ€.
@Getter
@Setter
public class UserDomain {
private String name;
private int age;
public boolean isTwenties() {
if (this.age >= 20 && this.age < 30){
return true;
}
return false;
}
}
μ¦, μμ μμ μμ lombokμ @Getter λ₯Ό ν΅ν΄ κ° νλμ getterκ° μμ±λκ³
MappingJackson2HttpMessageConverter μ ObjectMapperκ° μμ±λ getter λ€μ μ°Έμ‘°νμ¬ JSON νμμΌλ‘ μ§λ ¬ν νκ² λλ€.
@Getter
@Setter
public class UserDomain {
private String name;
private int age;
public boolean isTwenties() {
if (this.age >= 20 && this.age < 30){
return true;
}
return false;
}
// λ‘¬λ³΅μ΄ μμ±ν getter
public String getName(){
return this.name;
}
// λ‘¬λ³΅μ΄ μμ±ν getter
public String getAge(){
return this.age;
}
}
μ΄λ, isTwenties λ boolean νμ μ getterλΌκ³ μΈμλμ΄, λ©μλκ° μ€νλκ³ ν΄λΉ isTwenties μ 리ν΄κ° λν κ°μ΄ JSON λ°μ΄ν°μ λ€μ΄κ°κ² λ κ²μ΄λ€.
MappingJackson2HttpMessageConverter μ ObjectMapper κ° μ΄λ€ ν¨μλ₯Ό getterλ‘ μΈμνλμ§λ μ€μ μ½λλ₯Ό κΉλ΄μΌ μ νν μ μ μκ² μ§λ§, μλ§ public + parameterλ μκ³ () + λ©μλλͺ μ΄ getμΌλ‘ μμνλ€λ©΄ getterλ‘ μΈμνμ§ μμκΉ μΆλ€. (booleanμ κ²½μ° isλ‘ μμνλ κ²½μ°λ ν¬ν¨)
- μΆν, μ€μ λ‘ μ½λλ₯Ό νμΈν΄λ³΄κ³ μΆκ°ν΄ λκ² λ€.
- νμΈκ²°κ³Ό β¬οΈ
- μμ½ : μ€μ λ‘ νλΌλ―Έν°μ κ°μ νμΈ λ° getterPrefixμ κ°μΌλ‘ getterμΈμ§ νμΈνλ λ‘μ§μ΄ μλ€.
- μμΈν λ‘μ§μ λλ²κΉ κ³Ό ν¨κ» νμΈ κ°λ₯νλ λ무 볡μ‘
objectMapper.writeValueAsString(manager);
// μν κ²°κ³Ό
// POJOPropertiesCollector.collectAll μν
protected void collectAll() {
LinkedHashMap<String, POJOPropertyBuilder> props = new LinkedHashMap();
this._addFields(props); // νλκ° κ°μ Έμμ propsμ μΆκ°
this._addMethods(props); // λ©μλλ‘ νλκ° μΆκ°ν¨ <- μ¬κΈ°μ getter, setter νμΈν΄μ getterλ§ μμ΄λ μΆκ°λ¨
if (!this._classDef.isNonStaticInnerClass()) {
this._addCreators(props);
}
// μλ΅
}
protected void _addMethods(Map<String, POJOPropertyBuilder> props) {
Iterator var2 = this._classDef.memberMethods().iterator();
while(var2.hasNext()) {
AnnotatedMethod m = (AnnotatedMethod)var2.next();
int argCount = m.getParameterCount();
// νλΌλ―Έν°κ° 0κ°μ΄λ©΄ getterλ‘ νλ¨
if (argCount == 0) {
this._addGetterMethod(props, m, this._annotationIntrospector);
} else if (argCount == 1) {
this._addSetterMethod(props, m, this._annotationIntrospector);
} else if (argCount == 2 && Boolean.TRUE.equals(this._annotationIntrospector.hasAnySetter(m))) {
if (this._anySetters == null) {
this._anySetters = new LinkedList();
}
this._anySetters.add(m);
}
}
}
protected void _addGetterMethod(Map<String, POJOPropertyBuilder> props, AnnotatedMethod m, AnnotationIntrospector ai) {
Class<?> rt = m.getRawReturnType();
if (rt != Void.TYPE && (rt != Void.class || this._config.isEnabled(MapperFeature.ALLOW_VOID_VALUED_PROPERTIES))) {
if (Boolean.TRUE.equals(ai.hasAnyGetter(m))) {
if (this._anyGetters == null) {
this._anyGetters = new LinkedList();
}
this._anyGetters.add(m);
} else if (Boolean.TRUE.equals(ai.hasAsKey(this._config, m))) {
if (this._jsonKeyAccessors == null) {
this._jsonKeyAccessors = new LinkedList();
}
this._jsonKeyAccessors.add(m);
} else if (Boolean.TRUE.equals(ai.hasAsValue(m))) {
if (this._jsonValueAccessors == null) {
this._jsonValueAccessors = new LinkedList();
}
this._jsonValueAccessors.add(m);
} else {
PropertyName pn = ai.findNameForSerialization(m);
boolean nameExplicit = pn != null;
boolean visible;
String implName;
if (!nameExplicit) {
implName = ai.findImplicitPropertyName(m);
if (implName == null) {
// μ¬κΈ°μ getμΌλ‘ μμνλμ§ νλ¨ν΄μ implNameμ μΈν
νλ€
implName = this._accessorNaming.findNameForRegularGetter(m, m.getName());
}
if (implName == null) {
implName = this._accessorNaming.findNameForIsGetter(m, m.getName());
if (implName == null) {
return;
}
visible = this._visibilityChecker.isIsGetterVisible(m);
} else {
visible = this._visibilityChecker.isGetterVisible(m);
}
} else {
implName = ai.findImplicitPropertyName(m);
if (implName == null) {
implName = this._accessorNaming.findNameForRegularGetter(m, m.getName());
if (implName == null) {
implName = this._accessorNaming.findNameForIsGetter(m, m.getName());
}
}
if (implName == null) {
implName = m.getName();
}
if (pn.isEmpty()) {
pn = this._propNameFromSimple(implName);
nameExplicit = false;
}
visible = true;
}
implName = this._checkRenameByField(implName);
boolean ignore = ai.hasIgnoreMarker(m);
this._property(props, implName).addGetter(m, pn, nameExplicit, visible, ignore);
}
}
}
ν΄κ²°λ°©λ²
μ΄λ° κ²½μ°, μ¬μ€ κ°μ₯ κ°λ¨ν ν΄κ²° λ°©λ²μ DTO κ°μ²΄λ₯Ό μμ±νκ³ λΉμ¦λμ€ λ‘μ§μ λͺ¨λ μ κ±° ν λ°μ΄ν° μ λ¬μ©μΌλ‘ μ¬μ©νλκ² μλκΉ μΆλ€.
κ·Έλ΄μ μλ μν©μ΄λΌλ©΄ @JsonIgnore λ₯Ό λΆμ΄κ±°λ, ObjectMapperμ μ€μ μ λ°κΎΈλ λ°©λ²λ μ‘΄μ¬νλ€.
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);