如何创建状态表达式计算器?

问题描述 投票:0回答:0

我需要解决这个任务: 创建一个服务表达式值计算的 webapp。它必须服务于 PUT、GET、DELETE 请求并保持用户会话。

用户可以通过 PUT 请求将表达式用于评估或变量值。

要设置表达式,用户对 /calc/expression URI 执行 PUT 请求,提供表达式作为请求主体。

要设置变量,用户对 /calc/ URI 执行 PUT 请求,其中 是变量名(拉丁小写单个字符),变量值是请求主体。

用户可以通过执行另一个相同格式的 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);
    }
}

}

java servlets
© www.soinside.com 2019 - 2024. All rights reserved.