All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.moon.spring.web.error.RestExceptionEnum Maven / Gradle / Ivy

package com.moon.spring.web.error;

import com.moon.core.lang.StringUtil;
import com.moon.core.util.MapUtil;
import com.moon.core.util.SetUtil;
import com.moon.data.identifier.LongSequenceIdentifier;
import org.hibernate.TransientObjectException;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import java.net.MalformedURLException;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.SQLSyntaxErrorException;
import java.util.Map;

import static com.moon.spring.web.error.ErrorUtil.forErrorsByBindingResult;

/**
 * @author moonsky
 */
public enum RestExceptionEnum implements RestExceptionHandler {
    // mvc 表单提交验证错误
    onBingException("org.springframework.validation.BindException") {
        @Override
        public Object toMessage(Throwable ex) { return forErrorsByBindingResult((BindException) ex); }
    },
    // Hibernate-validator 验证错误
    onConstraintViolationException(ConstraintViolationException.class) {
        @Override
        public Map toMessage(Throwable throwable) {
            ConstraintViolationException ex = (ConstraintViolationException) throwable;
            return SetUtil.reduce(ex.getConstraintViolations(), (messages, violation, idx) -> {
                String property = violation.getPropertyPath().toString();
                String message = violation.getMessage();
                messages.put(property, message);
                return messages;
            }, MapUtil.newHashMap());
        }
    },
    // 参数校验错误,缺少 query 参数
    onMissingServletRequestParameterException("org.springframework.web.bind.MissingServletRequestParameterException") {
        @Override
        public Object toMessage(Throwable t) {
            MissingServletRequestParameterException e = (MissingServletRequestParameterException) t;
            return String.format("缺少参数: %s", e.getParameterName());
        }
    },
    // 页面请求时,@RequestBody 参数校验错误,包含所有错误字段
    onMethodArgumentNotValidException(MethodArgumentNotValidException.class, 400) {
        @Override
        public Object toMessage(Throwable t) {
            MethodArgumentNotValidException e = (MethodArgumentNotValidException) t;
            return forErrorsByBindingResult(e.getBindingResult());
        }
    },
    onHttpMessageNotReadableException("org.springframework.http.converter.HttpMessageNotReadableException",
        "参数错误,缺少: RequestBody"),
    onHttpMessageNotWritableException("org.springframework.http.converter.HttpMessageNotWritableException"),
    onHttpMediaTypeNotSupportedException("org.springframework.web.HttpMediaTypeNotSupportedException"),
    onHttpRequestMethodNotSupportedException("org.springframework.web.HttpRequestMethodNotSupportedException"),
    onTemplateInputException("org.thymeleaf.exceptions.TemplateInputException", "页面不存在: {}"),
    // 主要是在ManyToOne级联操作时遇到,
    // 比如new了一个新对象,在未保存之前将它保存进了一个新new的对象(也即不是持久态)
    onTransientObjectException(TransientObjectException.class, "{}"),
    onEntityNotFoundException("javax.persistence.EntityNotFoundException", "数据不存在", 400),
    // sql 语法错误
    onSQLSyntaxErrorException(SQLSyntaxErrorException.class, "数据库语法错误"),
    /**
     * 删除或更新时数据库对关联外键数据进行了错误操作
     * 如:当前数据被外键关联的数据没删除,就执行删除当前数据
     */
    onSQLIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException.class, "操作失败,当前数据已被引用"),
    onMySQLTransactionRollbackException("com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException", "数据库事务错误"),
    onSQLException(SQLException.class, "数据库错误"),
    onUnsupportedOperationException(UnsupportedOperationException.class, "不支持当前操作,请联系管理员或等待支持"),
    onIllegalArgumentException(IllegalArgumentException.class, "参数错误."),
    onIllegalStateException(IllegalStateException.class, "数据错误."),
    onMalformedURLException(MalformedURLException.class, "URL格式错误:{}", 400),
    onNullPointerException(NullPointerException.class, "参数或内部数据错误(NPE): null."),
    ;

    private final static transient LongSequenceIdentifier worker = LongSequenceIdentifier.of(29, 29);

    public static String nextSerialAsString() {
        return String.valueOf(worker.nextId());
    }

    private final String classname;
    private final String text;
    private final int status;

    RestExceptionEnum(Class type) { this(type, null); }

    RestExceptionEnum(Class type, int status) { this(type, null, status); }

    RestExceptionEnum(String classname) { this(classname, null); }

    RestExceptionEnum(String classname, int status) { this(classname, null, status); }

    RestExceptionEnum(Class type, String text) { this(type.getName(), text); }

    RestExceptionEnum(Class type, String text, int status) { this(type.getName(), text, status); }

    RestExceptionEnum(String classname, String text) { this(classname, text, 500); }

    RestExceptionEnum(String classname, String text, int status) {
        ExceptionService.doRegistry(this.classname = classname, this);
        this.status = status;
        this.text = text;
    }

    public String getConstMessage() { return text; }

    @Override
    public ResponseEntity onThrowable(HttpServletRequest request, HttpServletResponse response, Throwable ex)
        throws Throwable {
        return onThrowable(ex);
    }

    public Object toMessage(Throwable throwable) {
        return StringUtil.concat("[", nextSerialAsString(), "] ",

            StringUtil.format(getConstMessage(), throwable.getMessage()));
    }

    @Override
    @SuppressWarnings("all")
    public ResponseEntity onThrowable(Throwable ex) throws Throwable {
        try {
            Object result = toMessage(ex);
            return result instanceof ResponseEntity//
                   ? (ResponseEntity) result//
                   : ResponseEntity.status(status).body(result);
        } finally {
            // TODO logger 日志
            ex.printStackTrace();
        }
    }

    public static RestExceptionHandler forType(Class type) { return forType(type.getName()); }

    public static RestExceptionHandler forType(String classname) {
        return MvcExceptionUtil.getDefaultInstance().findRestExceptionHandler(classname);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy