SpringMVC在控制器方法之间放置通用代码的位置

时间:2019-01-28 05:52:48

标签: spring hibernate spring-mvc

我正在使用现有的代码库,并且在所有控制器方法中都看到了这种模式。开头声明了相同的变量,并将代码放置在try catch块中,所有方法中的代码也相同。我想知道是否有一种方法可以在BaseController中的方法之间推送通用代码。这样我就不必在每个方法中都声明公共变量,并且try catch块功能也可以委托给其他地方。

首先,我创建了一个BaseController类,并用@Controller注释了它,并将我的控制器扩展为其子类。然后,我将所有公共变量移至BaseController。问题是,一旦在控制器的方法中修改了这些变量,即使在下一个有问题的请求中,它们也会保留其值。

@RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
public ResponseEntity delete(@PathVariable("id") Integer id)
{
    HashMap response = new HashMap();
    boolean success = false;
    List errors = new ArrayList();
    HttpStatus httpStatus = HttpStatus.BAD_REQUEST;
    String message = "";
    try
    {
        purchaseInvoiceService.delete(id);
        success = true;
        message = "Purchase Invoice Deleted";
        httpStatus = HttpStatus.OK;

    } catch (Exception e)
    {
        errors.add(new ErrorMessage("error", e.getMessage()));
        e.printStackTrace();
    }

    response.put("success", success);
    response.put("errors", errors);
    response.put("message", message);
    return new ResponseEntity(response, httpStatus);
}

我想重构此模式,以便在每种方法中,我只需要仅包含对服务的调用,并有条件地设置成功和httpstatus变量(存在于BaseController中),然后使用存在于其中的response()方法返回响应添加数据变量的BaseController,其返回类型为ResponseEntity。

编辑1: 该端点当前返回所有购买发票的列表,它仅返回HashMap,后者已转换为JSON。我要说明的是,这些响应,成功,错误,httpStatus变量和将所有这些变量放入响应的部分HashMap()是每个控制器内部每个方法的一部分,我也想将它们重构为类似于ResponseFactory的东西。因此,我正在考虑将List传递给ResponseFactory,然后它将构造所有响应并以ResponseEntity的形式返回。只想知道我是否做对了。

@RequestMapping(method = RequestMethod.GET)
    public ResponseEntity getAll() {
        HashMap response = new HashMap();
        boolean success = false;
        List errors = new ArrayList();
        HttpStatus httpStatus = HttpStatus.BAD_REQUEST;
        String message = "";
        Map data = new HashMap();

        try {
            List<PurchaseInvoice> purchaseInvoices = purchaseInvoiceService.getAll();
            data.put("purchaseInvoices", purchaseInvoices);
            success = true;
            message = "Purchase Invoice List";
            httpStatus = httpStatus.OK;
        } catch (Exception e) {
            errors.add(new ErrorMessage("error", e.getMessage()));
            e.printStackTrace();
        }

        response.put("success", success);
        response.put("errors", errors);
        response.put("message", message);
        response.put("data", data);
        return new ResponseEntity(response, httpStatus);
    }

1 个答案:

答案 0 :(得分:0)

您的短语:“然后我将所有公共变量移至BaseController” 听起来令人困惑。

spring的控制器只是一个Singleton,由spring提供一个附加的“功能”:它作为Web端点公开(与您的特定问题无关)。

成为Singleton意味着ApplicationContext中有一个实例。

因此,如果变量是这样移动的:

 class BaseController {
       protected Field1 field1;
       protected Field2 field2;
        ....
 }

那么肯定存在问题,您实际上已经向控制器引入了一种状态,并且该状态在所有请求中共享。

长话短说,不要创建有状态的控制器

说重构的想法很好。重构的方式可能是错误的:

相反,我建议考虑以下重构:

使用一些静态方法创建类responseFactory:

class ResponseFactory {
     public static ResponseEntity success(String message) {
         here prepare the map with boolean success and everything
     }
}

现在控制器变为:

class Controller {

    public ResponseEntity delete(@PathVariable("id") Integer id) {
           purchaseInvoiceService.delete(id); // I'll talk about exceptions later
           return ResponseEntityFactory.success("Purchase Invoice Deleted");
    }
}

现在关于异常-这有点令人困惑-代码基本上说响应会成功尽管错误。 因此,如果您必须这样处理,则ResponseEntityFactory也必须获取错误列表或其他内容,但总的来说,Spring具有强大的异常处理机制来映射在后端(服务,DAO,有意义的非200响应。