From 9e239cd627e9b48b35768ed09bcf51474b4fd5b3 Mon Sep 17 00:00:00 2001
From: zf <1603559716@qq.com>
Date: 星期四, 07 九月 2023 16:32:18 +0800
Subject: [PATCH] Merge branch 'master' of https://sinanoaq.cn:8888/r/swspkmas into zf

---
 ruoyi-system/src/main/java/com/ruoyi/system/domain/resp/DistrictTreeRespDTO.java            |   27 +++
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java |   35 +++
 ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java                    |    5 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/BusinessException.java                |   74 ++++++++
 ruoyi-common/src/main/java/com/ruoyi/common/exception/ExceptionInfo.java                    |   46 +++++
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDistrictMapper.java                   |   15 +
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDistrictServiceImpl.java        |  126 ++++++++++++++
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDistrict.java                         |   25 ++
 ruoyi-system/src/main/java/com/ruoyi/system/service/SysDistrictService.java                 |   35 +++
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDistrictController.java        |   48 +++++
 ruoyi-common/src/main/java/com/ruoyi/common/constant/ResultConstants.java                   |   88 +++++++++
 11 files changed, 524 insertions(+), 0 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDistrictController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDistrictController.java
new file mode 100644
index 0000000..f2c2312
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDistrictController.java
@@ -0,0 +1,48 @@
+package com.ruoyi.web.controller.system;
+
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.domain.SysDistrict;
+import com.ruoyi.system.domain.resp.DistrictTreeRespDTO;
+import com.ruoyi.system.service.SysDistrictService;
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import java.io.Serializable;
+import java.util.List;
+
+import static com.ruoyi.common.core.domain.AjaxResult.success;
+
+/**
+ * @author hz
+ * @since 2023-09-07 13:13:47
+ */
+@RestController
+@RequestMapping("/system/sysDistrict/")
+public class SysDistrictController {
+    /**
+     * 获取所有
+     */
+    @Resource
+    private SysDistrictService sysDistrictService;
+
+    @GetMapping("/list")
+    public AjaxResult selectAll() {
+        List<SysDistrict> sysDistricts = sysDistrictService.selectAll();
+        return AjaxResult.success(sysDistricts);
+    }
+
+    /**
+     * 树状返回
+     *
+     */
+    @GetMapping("/tree")
+    public AjaxResult selectAllByTree() {
+        List<DistrictTreeRespDTO> sysDistricts = sysDistrictService.selectAllByTree();
+        return AjaxResult.success(sysDistricts);
+    }
+
+}
+
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
index 0080343..7c06bcf 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
@@ -27,6 +27,11 @@
      */
     public static final String SYS_DICT_KEY = "sys_dict:";
 
+
+    public static final String SYS_DISTRICT_LIST_KEY = "sys_district_list";
+
+    public static final String SYS_DISTRICT_TREE_KEY = "sys_district_tree";
+
     /**
      * 防重提交 redis key
      */
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/ResultConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/ResultConstants.java
new file mode 100644
index 0000000..bb680d9
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/ResultConstants.java
@@ -0,0 +1,88 @@
+package com.ruoyi.common.constant;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum ResultConstants {
+
+    //正常
+    OK(200,"成功"),
+
+    NOT_OK(500,"错误"),
+
+    //参数错误
+    PARAM_ERROR(300,"参数错误"),
+    PARAM_ERROR_NULL(301,"参数不能为空"),
+    PARAM_ERROR_ILLEGAL(301,"参数格式错误"),
+    PARAM_ERROR_OUT_OF_RANGE(302,"参数超出限制"),
+
+
+
+    //业务错误
+    BUSINESS_ERROR(400,"业务错误"),
+    BUSINESS_ERROR_ACCOUNT_NOT_EXIST(401,"用户不存在"),
+    BUSINESS_ERROR_ACCOUNT_STATU_ABNORMAL(402,"账号异常"),
+    BUSINESS_ERROR_ACCOUNT_OFFLINE(403,"用户未登录"),
+    BUSINESS_ERROR_PERMISSION_DENIALED(405,"操作未授权"),
+    BUSINESS_ERROR_OUT_OF_TIME(406,"业务超时"),
+    BUSINESS_ERROR_OBJECT_NOT_EXIST(407,"业务单元不存在"),
+    BUSINESS_ERROR_NOT_ALLOWED(408,"业务不允许"),
+    BUSINESS_ERROR_HTTP_METHOD_NOT_SUPPORT(409,"HTTP请求方法不支持"),
+    BUSINESS_ERROR_DATA_NOT_EXISIST(410,"数据不存在"),
+
+
+
+    //系统错误
+    SYSTEM_ERROR(500,"系统出错"),
+    SYSTEM_ERROR_API_FAIL(501,"接口错误"),
+    SYSTEM_ERROR_API_OUT_OF_TIME(502,"接口超时"),
+    SYSTEM_ERROR_DATABASE_FAIL(503,"数据库错误"),
+    SYSTEM_ERROR_SERIALIZA_FAIL(504,"序列化错误"),
+    //文件
+    FILE_NOT_EXISIST(600,"文件不存在"),
+    PATH_NOT_EXISIST(601,"文件路径不存在"),
+    MODULE_NOT_EXISIST(602,"模块不存在"),
+    FILE_UPLOAD_FAIL(603,"文件上传失败"),
+    FILE_DOWNLOAD_FAIL(604,"文件下载失败"),
+    FILE_DOWNLOAD_EXPERTION(605,"文件下载异常"),
+    ;
+
+
+
+    ResultConstants(Integer code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    private Integer code;
+    private String desc;
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public void setDesc(String desc) {
+        this.desc = desc;
+    }
+
+    static Map<Integer,ResultConstants> map;
+
+    static {
+        map = new HashMap<>();
+        for(ResultConstants rc : ResultConstants.values()){
+            map.put(rc.getCode(),rc);
+        }
+    }
+
+    public static ResultConstants prase(Integer code){
+        return map.get(code);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/BusinessException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/BusinessException.java
new file mode 100644
index 0000000..6b46590
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/BusinessException.java
@@ -0,0 +1,74 @@
+package com.ruoyi.common.exception;
+
+import com.ruoyi.common.constant.ResultConstants;
+
+public class BusinessException extends RuntimeException {
+
+    private Class causeClass;
+
+    private Integer code;
+
+    private String message;
+
+//    public BusinessException(ResultCode error) {
+//        super(error.getDesc());
+//        this.code = error.getCode();
+//        this.message = error.getDesc();
+//    }
+
+    public BusinessException(Class causeClass, ResultConstants error) {
+        super(error.getDesc());
+        this.causeClass = causeClass;
+        this.code = error.getCode();
+        this.message = error.getDesc();
+    }
+
+    public BusinessException(Class causeClass, ResultConstants error, String message) {
+        super(error.getDesc());
+        this.causeClass = causeClass;
+        this.code = error.getCode();
+        if(message != null && !message.isEmpty()){
+            this.message = message;
+        }else {
+            this.message = error.getDesc();
+        }
+    }
+
+//    public BusinessException(Integer code, String message) {
+//        super(message);
+//        this.code = code;
+//        this.message = message;
+//    }
+
+    public BusinessException(Class causeClass, Integer code, String message) {
+        super(message);
+        this.causeClass = causeClass;
+        this.code = code;
+        this.message = message;
+    }
+
+    public Class getCauseClass() {
+        return causeClass;
+    }
+
+    public void setCauseClass(Class causeClass) {
+        this.causeClass = causeClass;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/ExceptionInfo.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/ExceptionInfo.java
new file mode 100644
index 0000000..2d980b5
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/ExceptionInfo.java
@@ -0,0 +1,46 @@
+package com.ruoyi.common.exception;
+
+import java.time.LocalDateTime;
+
+public class ExceptionInfo {
+
+    private Class causeClass;
+
+    private LocalDateTime time;
+
+    private Integer code;
+
+    private String msg;
+
+    public Class getCauseClass() {
+        return causeClass;
+    }
+
+    public void setCauseClass(Class causeClass) {
+        this.causeClass = causeClass;
+    }
+
+    public LocalDateTime getTime() {
+        return time;
+    }
+
+    public void setTime(LocalDateTime time) {
+        this.time = time;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
index a3ec182..1d6d9e5 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
@@ -1,14 +1,22 @@
 package com.ruoyi.framework.web.exception;
 
 import javax.servlet.http.HttpServletRequest;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ruoyi.common.constant.ResultConstants;
+import com.ruoyi.common.exception.BusinessException;
+import com.ruoyi.common.exception.ExceptionInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.validation.BindException;
 import org.springframework.web.HttpRequestMethodNotSupportedException;
 import org.springframework.web.bind.MethodArgumentNotValidException;
 import org.springframework.web.bind.MissingPathVariableException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
 import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
 import com.ruoyi.common.constant.HttpStatus;
@@ -16,6 +24,8 @@
 import com.ruoyi.common.exception.DemoModeException;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.StringUtils;
+
+import java.time.LocalDateTime;
 
 /**
  * 全局异常处理器
@@ -27,6 +37,31 @@
 {
     private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    /**
+     * 通用异常
+     */
+    @ResponseBody
+    @ExceptionHandler(value = BusinessException.class)
+    public AjaxResult businessExceptionHandler(BusinessException e) throws JsonProcessingException {
+        ExceptionInfo exceptionInfo = new ExceptionInfo();
+        exceptionInfo.setTime(LocalDateTime.now());
+        exceptionInfo.setCode(e.getCode());
+        exceptionInfo.setMsg(e.getMessage());
+        exceptionInfo.setCauseClass(e.getCauseClass());
+        log.error(objectMapper.writeValueAsString(exceptionInfo));
+        if(e.getMessage() == null || e.getMessage().isEmpty()){
+            ResultConstants code = ResultConstants.prase(e.getCode());
+            if(code != null)
+                return AjaxResult.error(e.getCode(),code.getDesc());
+        }else {
+            return AjaxResult.error(e.getCode(),e.getMessage());
+        }
+        return AjaxResult.error();
+    }
+
     /**
      * 权限校验异常
      */
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDistrict.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDistrict.java
new file mode 100644
index 0000000..ccb8924
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDistrict.java
@@ -0,0 +1,25 @@
+package com.ruoyi.system.domain;
+
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author hz
+ * @since 2023-09-07 13:13:57
+ */
+@Data
+public class SysDistrict implements Serializable {
+    
+    private Long id;
+    
+    private String code;
+    
+    private String name;
+    
+    private String parentcode;
+
+    private Byte type;
+}
+
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/resp/DistrictTreeRespDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/resp/DistrictTreeRespDTO.java
new file mode 100644
index 0000000..70c74c8
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/resp/DistrictTreeRespDTO.java
@@ -0,0 +1,27 @@
+package com.ruoyi.system.domain.resp;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author Mr.huang
+ * @decription
+ * @date 2023/9/7 15:22
+ */
+@Data
+public class DistrictTreeRespDTO implements Serializable {
+
+    private Long id;
+
+    private String code;
+
+    private String name;
+
+    private String parentcode;
+
+    private Byte type;
+
+    private List<DistrictTreeRespDTO> children;
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDistrictMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDistrictMapper.java
new file mode 100644
index 0000000..43bc28d
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDistrictMapper.java
@@ -0,0 +1,15 @@
+package com.ruoyi.system.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.system.domain.SysDistrict;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author hz
+ * @since 2023-09-07 13:13:52
+ */
+@Repository
+public interface SysDistrictMapper extends BaseMapper<SysDistrict> {
+
+}
+
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/SysDistrictService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/SysDistrictService.java
new file mode 100644
index 0000000..aa48dd1
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/SysDistrictService.java
@@ -0,0 +1,35 @@
+package com.ruoyi.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.domain.SysDistrict;
+import com.ruoyi.system.domain.resp.DistrictTreeRespDTO;
+
+import java.util.List;
+
+/**
+ * @author hz
+ * @since 2023-09-07 13:13:57
+ */
+public interface SysDistrictService extends IService<SysDistrict> {
+
+    List<SysDistrict> selectAll();
+
+    /**
+     * 加载字典缓存数据
+     */
+    public void loadingDistrictCache();
+
+    /**
+     * 清空字典缓存数据
+     */
+    public void clearDistrictCache();
+
+    /**
+     * 重置字典缓存数据
+     */
+    public void resetDistrictCache();
+
+    List<DistrictTreeRespDTO> selectAllByTree();
+}
+
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDistrictServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDistrictServiceImpl.java
new file mode 100644
index 0000000..6e04e05
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDistrictServiceImpl.java
@@ -0,0 +1,126 @@
+package com.ruoyi.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.constant.CacheConstants;
+import com.ruoyi.common.constant.ResultConstants;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysDictData;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.exception.BusinessException;
+import com.ruoyi.common.utils.DictUtils;
+import com.ruoyi.common.utils.spring.SpringUtils;
+import com.ruoyi.system.domain.resp.DistrictTreeRespDTO;
+import com.ruoyi.system.mapper.SysDistrictMapper;
+import com.ruoyi.system.domain.SysDistrict;
+import com.ruoyi.system.service.SysDistrictService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.PostConstruct;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static com.ruoyi.common.utils.DictUtils.clearDictCache;
+
+/**
+ * @author hz
+ * @since 2023-09-07 13:13:58
+ */
+@Service("sysDistrictService")
+public class SysDistrictServiceImpl extends ServiceImpl<SysDistrictMapper, SysDistrict> implements SysDistrictService {
+
+    @PostConstruct
+    public void init()
+    {
+        loadingDistrictCache();
+    }
+
+    @Override
+    public List<SysDistrict> selectAll() {
+        if (SpringUtils.getBean(RedisCache.class).hasKey(CacheConstants.SYS_DISTRICT_LIST_KEY)){
+            List<SysDistrict> sysDistricts = SpringUtils.getBean(RedisCache.class).getCacheObject(CacheConstants.SYS_DISTRICT_LIST_KEY);
+            return sysDistricts;
+        }
+        List<SysDistrict> list = this.list();
+        SpringUtils.getBean(RedisCache.class).setCacheObject(CacheConstants.SYS_DISTRICT_LIST_KEY, list);
+        return list;
+    }
+
+    @Override
+    public void loadingDistrictCache()
+    {
+        List<SysDistrict> list = this.list();
+        if (!CollectionUtils.isEmpty(list)) {
+            SpringUtils.getBean(RedisCache.class).setCacheObject(CacheConstants.SYS_DISTRICT_LIST_KEY, list);
+        }
+        List<DistrictTreeRespDTO> treeRespDTOS = this.selectAllByTree();
+        if (!CollectionUtils.isEmpty(treeRespDTOS)) {
+            SpringUtils.getBean(RedisCache.class).setCacheObject(CacheConstants.SYS_DISTRICT_TREE_KEY, list);
+        }
+    }
+
+
+    @Override
+    public void clearDistrictCache()
+    {
+        if (SpringUtils.getBean(RedisCache.class).hasKey(CacheConstants.SYS_DISTRICT_LIST_KEY)){
+            SpringUtils.getBean(RedisCache.class).deleteObject(CacheConstants.SYS_DISTRICT_LIST_KEY);
+        }
+        if (SpringUtils.getBean(RedisCache.class).hasKey(CacheConstants.SYS_DISTRICT_TREE_KEY)){
+            SpringUtils.getBean(RedisCache.class).deleteObject(CacheConstants.SYS_DISTRICT_TREE_KEY);
+        }
+    }
+
+    /**
+     * 重置区划缓存数据
+     */
+    @Override
+    public void resetDistrictCache()
+    {
+        clearDistrictCache();
+        loadingDistrictCache();
+    }
+
+    @Override
+    public List<DistrictTreeRespDTO> selectAllByTree() {
+        if (SpringUtils.getBean(RedisCache.class).hasKey(CacheConstants.SYS_DISTRICT_TREE_KEY)){
+            List<DistrictTreeRespDTO> sysDistrictTree = SpringUtils.getBean(RedisCache.class).getCacheObject(CacheConstants.SYS_DISTRICT_TREE_KEY);
+            return sysDistrictTree;
+        }
+        List<SysDistrict> districts = this.selectAll();
+        if (CollectionUtils.isEmpty(districts)){
+            throw new BusinessException(this.getClass(), ResultConstants.SYSTEM_ERROR_DATABASE_FAIL,"区划信息获取失败");
+        }
+        //获取父节点,0表示父节点,让此次递归有个开头
+        List<DistrictTreeRespDTO> collect = districts.stream()
+                //父节点的id = 0,根据它开始进行实现。
+                .filter(e -> e.getParentcode().equals("0"))
+                .map(e ->{
+                    DistrictTreeRespDTO dto = new DistrictTreeRespDTO();
+                    BeanUtils.copyProperties(e,dto);
+                    //将过滤之后的数据来进行方法调用,拿到他的所有的子节点信息并进行封装
+                    dto.setChildren(getchildrens(dto, districts));
+                    return dto;
+                }).collect(Collectors.toList());
+        SpringUtils.getBean(RedisCache.class).setCacheObject(CacheConstants.SYS_DISTRICT_TREE_KEY, collect);
+        return collect;
+    }
+
+    private List<DistrictTreeRespDTO> getchildrens(DistrictTreeRespDTO root,List<SysDistrict> districts){
+        //root为每次最新的传递过来的数据,也就是上面过滤之后的 e ;
+        List<DistrictTreeRespDTO> collect = districts.stream()
+                //根据传递过来的 e ,拿到他的id,来查询出他的子节点id 这里有个特点 e.id = 子节点的父节点id
+                .filter(e -> Objects.equals(e.getParentcode(), root.getCode()))
+                .map(e -> {
+                    DistrictTreeRespDTO dto = new DistrictTreeRespDTO();
+                    BeanUtils.copyProperties(e,dto);
+                    dto.setChildren(getchildrens(dto, districts));
+                    //递归找到他的子节点,直到找到最后一个子节点为止,饼进行封装。
+                    return dto;
+                }).collect(Collectors.toList());
+        return collect;
+    }
+
+}
+

--
Gitblit v1.9.2