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

plus.extvos.restlet.controller.BaseController Maven / Gradle / Ivy

The newest version!
package plus.extvos.restlet.controller;

import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import plus.extvos.common.Result;
import plus.extvos.common.ResultCode;
import plus.extvos.common.Validator;
import plus.extvos.common.exception.ResultException;
import plus.extvos.common.utils.PrimitiveConvert;
import plus.extvos.common.utils.SpringContextHolder;
import plus.extvos.logging.annotation.Log;
import plus.extvos.logging.annotation.type.LogAction;
import plus.extvos.logging.annotation.type.LogLevel;
import plus.extvos.restlet.QuerySet;
import plus.extvos.restlet.annotation.Restlet;
import plus.extvos.restlet.config.RestletConfig;
import plus.extvos.restlet.intfs.OnCreate;
import plus.extvos.restlet.intfs.OnUpdate;
import plus.extvos.restlet.service.BaseService;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

/**
 * @author Mingcai SHEN
 * BaseController, a basic RESTful controller provice CURD operations
 */
public abstract class BaseController> extends BaseROController {

    private static final Logger log = LoggerFactory.getLogger(BaseController.class);

    private final boolean creatable;
    private final boolean updatable;
    private final boolean deletable;

    public BaseController() {
        super();
        log.debug("BaseController:> Initializing ... {} {}", getGenericType().getName(), getGenericType().isAnnotationPresent(Restlet.class));
        if (getGenericType().isAnnotationPresent(Restlet.class)) {
            Restlet r = getGenericType().getAnnotation(Restlet.class);
            creatable = r.creatable();
            updatable = r.updatable();
            deletable = r.deletable();
        } else if (this.getClass().isAnnotationPresent(Restlet.class)) {
            Restlet r = this.getClass().getAnnotation(Restlet.class);
            creatable = r.creatable();
            updatable = r.updatable();
            deletable = r.deletable();
        } else {
            creatable = true;
            updatable = true;
            deletable = true;
        }
    }

    private void updateFieldValue(T entity, String k, Object v) {
        try {
            Field f = entity.getClass().getDeclaredField(k);
            if (null != f) {
                f.setAccessible(true);
                f.set(entity, PrimitiveConvert.from(v.toString()).to(f.getType()));
            }
//                    PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(record.getClass(), k);
//                    if (null == pd) {
//                        continue;
//                    }
//                    pd.getWriteMethod().invoke(record, PrimitiveConvert.from(pathMap.get(k).toString()).to(pd.getPropertyType()));
        } catch (IllegalAccessException | NoSuchFieldException e) {
            log.error(">>", e);
//                    e.printStackTrace();
        }
    }

    @ApiOperation(value = "插入一条新记录", notes = "查询条件组织,请参考: https://github.com/extvos/quick-lib-restlet/blob/develop/README.md")
    @PostMapping()
    @Log(action = LogAction.CREATE, level = LogLevel.IMPORTANT, comment = "Generic CREATE")
    @Transactional(rollbackFor = Exception.class)
    public Result insertNew(
            @ApiParam(hidden = true) @PathVariable(required = false) Map pathMap,
            @Validated(OnCreate.class) @RequestBody T record) throws ResultException {
        log.debug("insertNew:> {}, {}", pathMap, record);
        record = preInsert(record);
        if (updatedCols(record) <= 0) {
            throw ResultException.badRequest("empty values for all fields is not allowed");
        }
        if (Validator.notEmpty(pathMap)) {
            for (String k : pathMap.keySet()) {
                updateFieldValue(record, k, pathMap.get(k));
//                try {
//                    Field f = record.getClass().getDeclaredField(k);
//                    if (null != f) {
//                        f.setAccessible(true);
//                        f.set(record, PrimitiveConvert.from(pathMap.get(k).toString()).to(f.getType()));
//                    }
////                    PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(record.getClass(), k);
////                    if (null == pd) {
////                        continue;
////                    }
////                    pd.getWriteMethod().invoke(record, PrimitiveConvert.from(pathMap.get(k).toString()).to(pd.getPropertyType()));
//                } catch (IllegalAccessException | NoSuchFieldException e) {
//                    log.error(">>", e);
////                    e.printStackTrace();
//                }
            }
        }
        int n = getService().insert(record);
        postInsert(record);
        Result ret = Result.data(record).success(ResultCode.CREATED);
        ret.setCount((long) n);
        return ret;
    }

    private int updatedCols(T record) {
        int updatedCols = 0;
        for (PropertyDescriptor pd : BeanUtils.getPropertyDescriptors(record.getClass())) {
            if ("class".equals(pd.getName())) {
                continue;
            }
            if (pd.getPropertyType().isPrimitive()) {
//                updatedCols += 1;
                throw ResultException.notImplemented("primitive property '" + pd.getName() + "' for entity is not allowed");
//                continue;
            }
            try {
                Object o = pd.getReadMethod().invoke(record);
                if (null != o) {
                    updatedCols += 1;
                }
            } catch (IllegalAccessException | InvocationTargetException ignore) {
            }
        }
        return updatedCols;
    }

    @ApiOperation(value = "按条件更新记录", notes = "查询条件组织,请参考: https://github.com/extvos/quick-lib-restlet/blob/develop/README.md")
    @PutMapping(value = {"", "/{id}"})
    @Log(action = LogAction.UPDATE, level = LogLevel.IMPORTANT, comment = "Generic UPDATE")
    @Transactional(rollbackFor = Exception.class)
    public Result updateByMap(
            @ApiParam(hidden = true) @PathVariable(required = false) Map pathMap,
            @ApiParam(hidden = true) @RequestParam(required = false) Map queryMap,
            @Validated(OnUpdate.class) @RequestBody T record) throws ResultException {
        QuerySet qs = buildQuerySet(pathMap, queryMap);
        if (updatedCols(record) <= 0) {
            throw ResultException.badRequest("no field to update");
        }
        int updated = 0;
        if (pathMap != null && pathMap.containsKey("id")) {
            Serializable id = convertId(pathMap.get("id").toString());
            record = preUpdate(id, record);
            updated = getService().updateById(id, record);
            postUpdate(id, record);
        } else {
            record = preUpdate(qs, record);
            if (Validator.notEmpty(pathMap)) {
                for (String k : pathMap.keySet()) {
                    updateFieldValue(record, k, pathMap.get(k));
//                    try {
//                        PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(record.getClass(), k);
//                        if (null == pd) {
//                            continue;
//                        }
//                        if (pd.getPropertyType().isPrimitive()) {
//                            // TODO: we are not able to determine primitive types by null, so ...
//                            continue;
//                        }
//                        if (null != pd.getReadMethod().invoke(record)) {
//                            throw ResultException.forbidden("not allowed to update '" + k + "'");
//                        }
//                    } catch (IllegalAccessException | InvocationTargetException ignored) {
//                    }
                }
            }
            updated = getService().updateByMap(qs, record);
            postUpdate(qs, record);
        }
        Result ret = Result.data(record).success();
        ret.setCount((long) updated);
        return ret;
    }


    @ApiOperation(value = "按条件删除记录", notes = "查询条件组织,请参考: https://github.com/extvos/quick-lib-restlet/blob/develop/README.md")
    @DeleteMapping(value = {"", "/{id}"})
    @Log(action = LogAction.DELETE, level = LogLevel.IMPORTANT, comment = "Generic DELETE")
    @Transactional(rollbackFor = Exception.class)
    public Result deleteByMap(
            @ApiParam(hidden = true) @PathVariable(required = false) Map pathMap,
            @ApiParam(hidden = true) @RequestParam(required = false) Map queryMap) throws ResultException {
        QuerySet qs = buildQuerySet(pathMap, queryMap);
        int deleted = 0;
        if (pathMap != null && pathMap.containsKey("id")) {
            Serializable id = convertId(pathMap.get("id").toString());
            preDelete(id);
            deleted = getService().deleteById(id);
            postDelete(id);
        } else {
            qs = preDelete(qs);
            deleted = getService().deleteByMap(qs);
            postDelete(qs);
        }

        RestletConfig config = SpringContextHolder.getBean(RestletConfig.class);
        if (config.isDeleteResponseBody()) {
            return Result.data(deleted).success(ResultCode.OK);
        } else {
            return Result.data(deleted).success(ResultCode.NO_CONTENT);
        }
    }

    /* The following method can be overridden by extended classes */

    public T preInsert(T entity) throws ResultException {
        if (!creatable) {
            throw ResultException.forbidden();
        }
        return entity;
    }

    public T preUpdate(Serializable id, T entity) throws ResultException {
        if (!updatable) {
            throw ResultException.forbidden();
        }
        return entity;
    }

    public T preUpdate(QuerySet qs, T entity) throws ResultException {
        if (!updatable) {
            throw ResultException.forbidden();
        }
        return entity;
    }

    public void preDelete(Serializable id) throws ResultException {
        if (!deletable) {
            throw ResultException.forbidden();
        }
    }

    public QuerySet preDelete(QuerySet qs) throws ResultException {
        if (!deletable) {
            throw ResultException.forbidden();
        }
        return qs;
    }

    public void postInsert(T entity) throws ResultException {

    }

    public void postUpdate(Serializable id, T entity) throws ResultException {

    }

    public void postUpdate(QuerySet qs, T entity) throws ResultException {

    }

    public void postDelete(Serializable id) throws ResultException {

    }

    public void postDelete(QuerySet qs) throws ResultException {

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy