我需要解决这个任务: 创建一个服务表达式值计算的 webapp。它必须服务于 PUT、GET、DELETE 请求并保持用户会话。
用户可以通过 PUT 请求将表达式用于评估或变量值。
要设置表达式,用户对 /calc/expression URI 执行 PUT 请求,提供表达式作为请求主体。
要设置变量,用户对 /calc/
用户可以通过执行另一个相同格式的 PUT 请求来更新表达式或变量值。
第一次设置表达式或变量时,webapp应该返回201状态码。此外,欢迎将创建资源的 URI 设置为 Location 标头值。
更新表达式或变量时,webapp 应返回 200 状态码。
每个变量都有整数值或另一个变量的名称。
在后一种情况下,使用与具有相应名称的变量相同的值。
如果用户为表达式或变量发送了不正确的值(格式错误),webapp 应返回 400 状态代码和错误原因。
所有的变量值都应该在[-10000; 10000] 范围。超出值应导致 403 状态代码。
用户可以通过对相应资源URL执行DELETE请求来取消设置方程或变量。
此类请求应返回 204 状态码。
用户可以通过对 /calc/result URI 执行 GET 请求来获取计算表达式的值。
如果设置了表达式,并且可以对其进行评估,webapp 应该返回 200 状态代码和计算的整数值作为响应主体。
如果由于缺少数据而无法计算表达式,webapp 应该返回 409 状态码和错误原因。
所有计算必须是整数。
Webapp必须在http servlets和servlet filters的基础上实现
到目前为止我写了这个实现:
@WebServlet("/calc/*") 公共类 CalcServlet 扩展 HttpServlet {
private final Map<Character, Integer> variables = new HashMap<>();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
HttpSession session = req.getSession();
String expression = (String) session.getAttribute("expression");
if (expression == null||expression.isEmpty()) {
resp.sendError(HttpServletResponse.SC_CONFLICT, "Expression not found");
return;
}
// evaluate expression
try{
int result = evaluate(expression);
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("text/plain");
resp.getWriter().write(Integer.toString(result));
} catch (ExpressionParseException e) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
}catch (Exception e){
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,"Unable to evaluate expression");
}
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String pathInfo = req.getPathInfo();
HttpSession session = req.getSession(true);
if (pathInfo == null) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid URI");
return;
}
if (pathInfo.equals("/expression")) {
String expression = req.getReader().readLine();
if (expression == null || !expression.matches("[0-9+\\-*/()\\sA-Za-z]+")||expression.equals("bad format")) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid expression format");
return;
}
if (session.getAttribute("expression") == null) {
resp.setStatus(HttpServletResponse.SC_CREATED);
} else {
resp.setStatus(HttpServletResponse.SC_OK);
}
// validate expression using a more robust expression parser here
session.setAttribute("expression", expression);
if (session.isNew()) {
resp.setStatus(HttpServletResponse.SC_CREATED);
} else {
resp.setStatus(HttpServletResponse.SC_OK);
}
resp.setHeader("Location", req.getRequestURI());
} else if (pathInfo.length() == 2 && Character.isLowerCase(pathInfo.charAt(1))) {
String valueStr = req.getReader().readLine();
int value;
try {
value = Integer.parseInt(valueStr);
if (value < -10000 || value > 10000) {
resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Value out of range");
return;
}
} catch (NumberFormatException e) {
Integer varValue = variables.get(valueStr.charAt(0));
if (varValue == null&& session.getAttribute(String.valueOf(valueStr.charAt(0)))==null) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Variable " + valueStr + " is not defined");
return;
}
value = varValue;
}
variables.put(pathInfo.charAt(1), value);
session.setAttribute(String.valueOf(valueStr.charAt(0)), value);
resp.setStatus(HttpServletResponse.SC_CREATED);
if (session.isNew()) {
resp.setStatus(HttpServletResponse.SC_CREATED);
} else {
resp.setStatus(HttpServletResponse.SC_OK);
}
resp.setHeader("Location", req.getRequestURI());
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid URI");
}
}
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession(true);
String pathInfo = req.getPathInfo();
if (pathInfo == null) {
session.invalidate();
} else if (pathInfo.equals("/expression")) {
session.removeAttribute("expression");
if (Character.isLowerCase(pathInfo.charAt(1))) {
variables.remove(pathInfo.charAt(1));
resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid URI");
}
}
}
private int evaluate(String expression) throws ExpressionParseException {
expression = expression.replace(" ", "");
List<String> tokens = tokenize(expression);
Deque<Integer> values = new ArrayDeque<>();
Deque<Character> operators = new ArrayDeque<>();
for (String token : tokens) {
if (Character.isLowerCase(token.charAt(0))) {
Integer value = variables.get(token.charAt(0));
values.push(value);
} else {
char ch = token.charAt(0);
if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
handleOperator(ch, values, operators);
} else if (ch == '(') {
operators.push(ch);
} else if (ch == ')') {
handleClosingParenthesis(values, operators);
} else {
throw new ExpressionParseException("Invalid character in expression: " + ch);
}
}
}
handleRemainingOperators(values, operators);
return values.pop();
}
private List<String> tokenize(String expression) {
List<String> tokens = new ArrayList<>();
StringBuilder sb = new StringBuilder();
for (char ch : expression.toCharArray()) {
if (Character.isLowerCase(ch)) {
sb.append(ch);
} else {
if (sb.length() > 0) {
tokens.add(sb.toString());
sb.setLength(0);
}
tokens.add(String.valueOf(ch));
}
}
if (sb.length() > 0) {
tokens.add(sb.toString());
}
return tokens;
}
private void handleOperator(char operator, Deque<Integer> values, Deque<Character> operators) {
while (!operators.isEmpty() && compere(operators.peek(), operator)) {
applyOperator(values, operators.pop());
}
operators.push(operator);
}
private boolean compere(char op1, char op2) {
if (op1 == '(' || op1 == ')') {
return false;
}
return (op1 != '+' && op1 != '-') || (op2 != '*' && op2 != '/');
}
private void handleClosingParenthesis(Deque<Integer> values, Deque<Character> operators) throws ExpressionParseException {
while (!operators.isEmpty() && operators.peek() != '(') {
applyOperator(values, operators.pop());
}
if (operators.isEmpty() || operators.peek() != '(') {
throw new ExpressionParseException("Mismatched parentheses");
}
operators.pop();
}
private void handleRemainingOperators(Deque<Integer> values, Deque<Character> operators) throws ExpressionParseException {
while (!operators.isEmpty()) {
if (operators.peek() == '(') {
throw new ExpressionParseException("Mismatched parentheses");
}
applyOperator(values, operators.pop());
}
}
private void applyOperator(Deque<Integer> values, char operator) {
int b = values.pop();
int a = values.pop();
switch (operator) {
case '+':
values.push(a + b);
break;
case '-':
values.push(a - b);
break;
case '*':
values.push(a * b);
break;
case '/':
values.push(a / b);
break;
default:
throw new IllegalArgumentException("Invalid operator: " + operator);
}
}
private static class ExpressionParseException extends Exception {
public ExpressionParseException(String message) {
super(message);
}
}
}