-
Notifications
You must be signed in to change notification settings - Fork 16
π 4λ¨κ³ - Controller λ©μλ μΈμ λ§€ν #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: woo-yu
Are you sure you want to change the base?
Changes from all commits
30ef3e5
36b39f5
758a99c
ef782d2
477d673
320f09d
fa68f4f
1f515cc
1bf4d48
6f4c02a
6c2ebc9
d1ebe40
6bff222
3845f67
125fbff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.interface21.web.parameter; | ||
|
|
||
| import jakarta.servlet.http.HttpServletRequest; | ||
|
|
||
| import java.lang.reflect.Method; | ||
| import java.lang.reflect.Parameter; | ||
|
|
||
| public interface ParameterParser { | ||
| Object parse(final Method method, final Parameter parameter, final HttpServletRequest request); | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package com.interface21.web.parameter; | ||
|
|
||
| import jakarta.servlet.http.HttpServletRequest; | ||
| import jakarta.servlet.http.HttpServletResponse; | ||
|
|
||
| import java.lang.reflect.Method; | ||
| import java.lang.reflect.Parameter; | ||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.List; | ||
| import java.util.Objects; | ||
|
|
||
| public class ParameterParsers { | ||
|
|
||
| private final List<ParameterParser> parsers = new ArrayList<>(Arrays.asList(new PathVariableParser(), new QueryParamParser())); | ||
|
|
||
| public ParameterParsers() { | ||
|
|
||
| } | ||
|
|
||
| public ParameterParsers(ParameterParser... parsers) { | ||
| this.parsers.addAll(Arrays.asList(parsers)); | ||
| } | ||
|
Comment on lines
+13
to
+23
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ParameterParsers μΌκΈμ»¬λ μ
μ λν΄νΈλ‘ PathVariableParser μ QueryParamParser λ₯Ό κ°μ§κ³ , |
||
|
|
||
| public Object[] parse(final Method method, final HttpServletRequest request, final HttpServletResponse response) { | ||
| var parameters = method.getParameters(); | ||
| var params = new Object[parameters.length]; | ||
|
|
||
| for (int i = 0; i < parameters.length; i++) { | ||
| var parsedParam = parse(method, parameters[i], request, response); | ||
| params[i] = parsedParam; | ||
| } | ||
| return params; | ||
| } | ||
|
|
||
| private Object parse(final Method method, final Parameter parameter, final HttpServletRequest request, final HttpServletResponse response) { | ||
| if (parameter.getType().equals(HttpServletRequest.class)) { | ||
| return request; | ||
| } | ||
| if (parameter.getType().equals(HttpServletResponse.class)) { | ||
| return response; | ||
| } | ||
|
|
||
| return parsers.stream().map(parser -> parser.parse(method, parameter, request)).filter(Objects::nonNull).findFirst() | ||
| .orElseThrow(IllegalArgumentException::new); | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| package com.interface21.web.parameter; | ||
|
|
||
| import com.interface21.web.support.TypedParsers; | ||
| import jakarta.servlet.http.HttpServletRequest; | ||
|
|
||
| import java.lang.reflect.Constructor; | ||
| import java.lang.reflect.Field; | ||
| import java.lang.reflect.Method; | ||
| import java.lang.reflect.Parameter; | ||
| import java.util.Arrays; | ||
|
|
||
| public class ParameterTypedParser implements ParameterParser { | ||
| private final Class<?> type; | ||
|
|
||
| public ParameterTypedParser(Class<?> type) { | ||
| this.type = type; | ||
| } | ||
|
|
||
| @Override | ||
| public Object parse(Method method, Parameter parameter, HttpServletRequest request) { | ||
| if (!parameter.getType().equals(type)) { | ||
| return null; | ||
| } | ||
| var constructors = type.getDeclaredConstructors(); | ||
| var fullyFieldConstructor = Arrays.stream(constructors).filter(constructor -> constructor.getParameterCount() == type.getDeclaredFields().length).findFirst(); | ||
| if (fullyFieldConstructor.isPresent()) { | ||
| return parseFully(fullyFieldConstructor.get(), request); | ||
| } | ||
| var defaultConstructor = Arrays.stream(constructors).filter(constructor -> constructor.getParameterCount() == 0).findFirst(); | ||
| return defaultConstructor.map(constructor -> parseDefault(constructor, request)).orElse(null); | ||
| } | ||
|
|
||
| private Object parseFully(Constructor<?> constructor, HttpServletRequest request) { | ||
| var parameters = constructor.getParameters(); | ||
| var args = new Object[parameters.length]; | ||
| for (int i = 0; i < parameters.length; i++) { | ||
| args[i] = TypedParsers.parse(parameters[i].getType(), request.getParameter(parameters[i].getName())); | ||
| } | ||
| try { | ||
| return constructor.newInstance(args); | ||
| } catch (Exception e) { | ||
| throw new IllegalArgumentException(); | ||
| } | ||
| } | ||
|
|
||
| private Object parseDefault(Constructor<?> constructor, HttpServletRequest request) { | ||
| try { | ||
| var instance = constructor.newInstance(); | ||
| for (Field field : type.getDeclaredFields()) { | ||
| field.setAccessible(true); | ||
| field.set(instance, TypedParsers.parse(field.getType(), request.getParameter(field.getName()))); | ||
| } | ||
| return instance; | ||
| } catch (Exception e) { | ||
| throw new IllegalArgumentException(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package com.interface21.web.parameter; | ||
|
|
||
|
|
||
| import com.interface21.web.bind.annotation.PathVariable; | ||
| import com.interface21.web.bind.annotation.RequestMapping; | ||
| import com.interface21.web.support.PathPatternUtil; | ||
| import com.interface21.web.support.TypedParsers; | ||
| import jakarta.servlet.http.HttpServletRequest; | ||
|
|
||
| import java.lang.reflect.Method; | ||
| import java.lang.reflect.Parameter; | ||
|
|
||
| public class PathVariableParser implements ParameterParser { | ||
|
|
||
| @Override | ||
| public Object parse(Method method, Parameter parameter, HttpServletRequest request) { | ||
| var variable = parameter.getAnnotation(PathVariable.class); | ||
| var requestMapping = method.getAnnotation(RequestMapping.class); | ||
| if (variable == null || requestMapping == null) { | ||
| return null; | ||
| } | ||
| var name = variable.name(); | ||
| if (name.isBlank()) { | ||
| name = parameter.getName(); | ||
| } | ||
| var param = PathPatternUtil.getUriValue(requestMapping.value(), request.getRequestURI(), name); | ||
| if (param == null) { | ||
| return null; | ||
| } | ||
| return TypedParsers.parse(parameter.getType(), param); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package com.interface21.web.parameter; | ||
|
|
||
|
|
||
| import com.interface21.web.support.TypedParsers; | ||
| import jakarta.servlet.http.HttpServletRequest; | ||
|
|
||
| import java.lang.reflect.Method; | ||
| import java.lang.reflect.Parameter; | ||
|
|
||
| public class QueryParamParser implements ParameterParser { | ||
|
|
||
| @Override | ||
| public Object parse(Method method, Parameter parameter, HttpServletRequest request) { | ||
| var param = request.getParameter(parameter.getName()); | ||
| if (param == null) { | ||
| return null; | ||
| } | ||
| return TypedParsers.parse(parameter.getType(), param); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| package com.interface21.web.support; | ||
|
|
||
| import java.util.*; | ||
| import java.util.regex.Pattern; | ||
|
|
||
| public class PathPatternParser { | ||
|
|
||
| private final Pattern pattern; | ||
| private final List<String> variableNames = new ArrayList<>(); | ||
|
|
||
| public PathPatternParser(String pattern) { | ||
| String regex = buildRegex(pattern); | ||
| this.pattern = Pattern.compile(regex); | ||
| } | ||
|
|
||
| private String buildRegex(String pattern) { | ||
| var matcher = Pattern.compile("\\{([^}]+)}").matcher(pattern); | ||
| StringBuffer buffer = new StringBuffer(); | ||
| while (matcher.find()) { | ||
| variableNames.add(matcher.group(1)); | ||
| matcher.appendReplacement(buffer, "([^/]+)"); | ||
| } | ||
| matcher.appendTail(buffer); | ||
| return buffer.toString(); | ||
| } | ||
|
|
||
| public boolean matches(String path) { | ||
| return pattern.matcher(path).matches(); | ||
| } | ||
|
|
||
| public Map<String, String> extractUriVariables(String path) { | ||
| var matcher = pattern.matcher(path); | ||
| if (!matcher.matches()) { | ||
| return Collections.emptyMap(); | ||
| } | ||
| Map<String, String> variables = new HashMap<>(); | ||
| for (int i = 0; i < variableNames.size(); i++) { | ||
| variables.put(variableNames.get(i), matcher.group(i + 1)); | ||
| } | ||
| return variables; | ||
| } | ||
|
Comment on lines
+27
to
+41
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PathPatternUtil μ λν ν μ€νΈλ μμ±ν΄μ£Όμ ¨μ§λ§, μ μ PathPatternParser κ°μ²΄μ λν΄μλ ν μ€νΈ μμ±ν΄μ£Όμμ§ μμλλ° λ³΄μ λΆνλ립λλ€. |
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,24 @@ | ||||||||
| package com.interface21.web.support; | ||||||||
|
|
||||||||
| import java.util.Map; | ||||||||
|
|
||||||||
| public class PathPatternUtil { | ||||||||
|
|
||||||||
|
Comment on lines
+5
to
+6
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
μ λ μ νΈμ± ν΄λμ€μ κ²½μ° μΈμ€ν΄μ€μ μμ±μ΄ λΆκ°λ₯νλλ‘, |
||||||||
| public static String getUriValue(String pattern, String path, String key) { | ||||||||
| final Map<String, String> uriVariables = getUriVariables(pattern, path); | ||||||||
| return uriVariables.get(key); | ||||||||
| } | ||||||||
|
|
||||||||
| public static Map<String, String> getUriVariables(String pattern, String path) { | ||||||||
| if (!isUrlMatch(pattern, path)) { | ||||||||
| return Map.of(); | ||||||||
| } | ||||||||
| final PathPatternParser parser = new PathPatternParser(pattern); | ||||||||
| return parser.extractUriVariables(path); | ||||||||
| } | ||||||||
|
|
||||||||
| public static boolean isUrlMatch(String pattern, String path) { | ||||||||
| final PathPatternParser parser = new PathPatternParser(pattern); | ||||||||
| return parser.matches(path); | ||||||||
| } | ||||||||
| } | ||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package com.interface21.web.support; | ||
|
|
||
|
|
||
| import java.util.function.Function; | ||
|
|
||
| public class TypedParser { | ||
| protected static final TypedParser STRING = new TypedParser(String.class, (s) -> s); | ||
| protected static final TypedParser INT = new TypedParser(int.class, Integer::parseInt); | ||
| protected static final TypedParser WRAPPER_INTEGER = new TypedParser(Integer.class, Integer::parseInt); | ||
| protected static final TypedParser LONG = new TypedParser(long.class, Long::parseLong); | ||
| protected static final TypedParser WRAPPER_LONG = new TypedParser(Long.class, Integer::parseInt); | ||
| protected static final TypedParser BOOLEAN = new TypedParser(boolean.class, Boolean::parseBoolean); | ||
| protected static final TypedParser WRAPPER_BOOLEAN = new TypedParser(Boolean.class, Boolean::parseBoolean); | ||
| protected static final TypedParser SHORT = new TypedParser(short.class, Short::parseShort); | ||
| protected static final TypedParser WRAPPER_SHORT = new TypedParser(Short.class, Short::parseShort); | ||
| protected static final TypedParser FLOAT = new TypedParser(float.class, Float::parseFloat); | ||
| protected static final TypedParser WRAPPER_FLOAT = new TypedParser(Float.class, Float::parseFloat); | ||
| protected static final TypedParser DOUBLE = new TypedParser(double.class, Double::parseDouble); | ||
| protected static final TypedParser WRAPPER_DOUBLE = new TypedParser(Double.class, Double::parseDouble); | ||
| protected static final TypedParser CHAR = new TypedParser(char.class, s -> s.charAt(0)); | ||
| protected static final TypedParser WRAPPER_CHAR = new TypedParser(Character.class, s -> s.charAt(0)); | ||
|
Comment on lines
+6
to
+21
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TypedParser λ΄λΆμ μ μΈλ static μμλ€μ TypedParsers μμλ§ μ°μ΄λ λ―νλ°, TypedParsers ν΄λμ€ μμμ μ΅λͺ μΌλ‘ μ μΈν μλ μμ κ² κ°μμμ. |
||
|
|
||
| private final Class<?> type; | ||
| private final Function<String, Object> parser; | ||
|
|
||
| public TypedParser(Class<?> type, Function<String, Object> parser) { | ||
| this.type = type; | ||
| this.parser = parser; | ||
| } | ||
|
|
||
| protected boolean canParse(Class<?> type) { | ||
| return type.equals(this.type); | ||
| } | ||
|
|
||
| protected Object parse(String value) { | ||
| return parser.apply(value); | ||
| } | ||
|
|
||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package com.interface21.web.support; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| public class TypedParsers { | ||
| private static List<TypedParser> parserList = new ArrayList<>(List.of(TypedParser.STRING, TypedParser.INT, TypedParser.WRAPPER_INTEGER, TypedParser.LONG, TypedParser.WRAPPER_LONG, TypedParser.BOOLEAN, TypedParser.WRAPPER_BOOLEAN, TypedParser.SHORT, TypedParser.WRAPPER_SHORT, TypedParser.FLOAT, TypedParser.WRAPPER_FLOAT, TypedParser.DOUBLE, TypedParser.WRAPPER_DOUBLE, TypedParser.CHAR, TypedParser.WRAPPER_CHAR)); | ||
|
|
||
|
|
||
| public static void add(TypedParser... parsers) { | ||
| parserList.addAll(List.of(parsers)); | ||
| } | ||
|
Comment on lines
+10
to
+12
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. μ λ©μλλ μ΄λμ μ°μ΄λμ§, λ¬΄μ¨ μλλ‘ λ§λ κ²μΈμ§ κΆκΈν΄μ μ¬μμ΄λ΄
λλ€. |
||
|
|
||
| public static Object parse(final Class<?> type, final String value) { | ||
| return parserList.stream().filter(parser -> parser.canParse(type)).findFirst() | ||
| .orElseThrow(IllegalArgumentException::new) | ||
| .parse(value); | ||
| } | ||
|
Comment on lines
+14
to
+18
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. νμ¬ TypeParser λ₯Ό μ°Ύμ λ List μμ findFirst λ₯Ό νλλ°, |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ParameterParser λ₯Ό μΈν°νμ΄μ€λ‘ μ μν΄μ£Όμκ³ ,
μ΄μ λν 3κ°μ§ ꡬν체λ₯Ό λ§λ€μ΄μ£Όμ μ μ’μ΅λλ€. π
(ParameterTypedParser, PathVariableParser, QueryParamParser)