inleft
2022-02-17 4d51af31b49927bf401e432138d584f9ef40ef22
友链添加
15 files added
5 files modified
1 files renamed
1640 ■■■■■ changed files
_web/src/api/modular/main/blogfriendshiplink/blogFriendshipLinkManage.js 86 ●●●●● patch | view | raw | blame | history
_web/src/views/main/blogfriendshiplink/addForm.vue 119 ●●●●● patch | view | raw | blame | history
_web/src/views/main/blogfriendshiplink/editForm.vue 140 ●●●●● patch | view | raw | blame | history
_web/src/views/main/blogfriendshiplink/index.vue 309 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogStatistics/BlogStatisticsController.java 16 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogarticle/entity/BlogArticle.java 6 ●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogarticletype/controller/BlogArticleTypeOutsideController.java 3 ●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/controller/BlogFriendshipLinkController.java 148 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/controller/BlogLinkOutsideController.java 112 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/entity/BlogFriendshipLink.java 111 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/enums/BlogFriendshipLinkExceptionEnum.java 64 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/mapper/BlogFriendshipLinkMapper.java 37 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/mapper/mapping/BlogFriendshipLinkMapper.xml 5 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/param/BlogFriendshipLinkParam.java 104 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/param/BlogFriendshipLinkVo.java 76 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/param/BlogLinkVo.java 45 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/service/BlogFriendshipLinkService.java 97 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/service/impl/BlogFriendshipLinkServiceImpl.java 140 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/resources/application-local.yml 5 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/resources/application-prod.yml 14 ●●●●● patch | view | raw | blame | history
snowy-main/src/main/resources/application.yml 3 ●●●● patch | view | raw | blame | history
_web/src/api/modular/main/blogfriendshiplink/blogFriendshipLinkManage.js
New file
@@ -0,0 +1,86 @@
import { axios } from '@/utils/request'
/**
 * 查询友情链接
 *
 * @author inleft
 * @date 2022-02-17 14:50:13
 */
export function blogFriendshipLinkPage (parameter) {
  return axios({
    url: '/blogFriendshipLink/page',
    method: 'get',
    params: parameter
  })
}
/**
 * 友情链接列表
 *
 * @author inleft
 * @date 2022-02-17 14:50:13
 */
export function blogFriendshipLinkList (parameter) {
  return axios({
    url: '/blogFriendshipLink/list',
    method: 'get',
    params: parameter
  })
}
/**
 * 添加友情链接
 *
 * @author inleft
 * @date 2022-02-17 14:50:13
 */
export function blogFriendshipLinkAdd (parameter) {
  return axios({
    url: '/blogFriendshipLink/add',
    method: 'post',
    data: parameter
  })
}
/**
 * 编辑友情链接
 *
 * @author inleft
 * @date 2022-02-17 14:50:13
 */
export function blogFriendshipLinkEdit (parameter) {
  return axios({
    url: '/blogFriendshipLink/edit',
    method: 'post',
    data: parameter
  })
}
/**
 * 删除友情链接
 *
 * @author inleft
 * @date 2022-02-17 14:50:13
 */
export function blogFriendshipLinkDelete (parameter) {
  return axios({
    url: '/blogFriendshipLink/delete',
    method: 'post',
    data: parameter
  })
}
/**
 * 导出友情链接
 *
 * @author inleft
 * @date 2022-02-17 14:50:13
 */
export function blogFriendshipLinkExport (parameter) {
  return axios({
    url: '/blogFriendshipLink/export',
    method: 'get',
    params: parameter,
    responseType: 'blob'
  })
}
_web/src/views/main/blogfriendshiplink/addForm.vue
New file
@@ -0,0 +1,119 @@
<template>
  <a-modal title="新增友情链接" :width="900" :visible="visible" :confirmLoading="confirmLoading" @ok="handleSubmit"
    @cancel="handleCancel">
    <a-spin :spinning="confirmLoading">
      <a-form :form="form">
        <a-form-item label="名称" :labelCol="labelCol" :wrapperCol="wrapperCol" has-feedback>
          <a-input placeholder="请输入名称" v-decorator="['name', {rules: [{required: true, message: '请输入名称!'}]}]" />
        </a-form-item>
        <a-form-item label="url地址" :labelCol="labelCol" :wrapperCol="wrapperCol" has-feedback>
          <a-input placeholder="请输入url地址" v-decorator="['url', {rules: [{required: true, message: '请输入url地址!'}]}]" />
        </a-form-item>
        <a-form-item label="头像地址" :labelCol="labelCol" :wrapperCol="wrapperCol" has-feedback>
          <a-input placeholder="请输入头像地址"
            v-decorator="['avatar', {rules: [{required: false, message: '请输入头像地址!'}]}]" />
        </a-form-item>
        <a-form-item label="描述" :labelCol="labelCol" :wrapperCol="wrapperCol" has-feedback>
          <a-input placeholder="请输入描述" v-decorator="['remark', {rules: [{required: false, message: '请输入描述!'}]}]" />
        </a-form-item>
        <a-form-item label="链接类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
          <a-radio-group placeholder="请选择链接类型"
            v-decorator="['linkType',{rules: [{ required: true, message: '请选择链接类型!' }]}]">
            <a-radio v-for="(item,index) in linkTypeData" :key="index" :value="item.code">{{ item.name }}</a-radio>
          </a-radio-group>
        </a-form-item>
        <a-form-item label="权重" :labelCol="labelCol" :wrapperCol="wrapperCol" has-feedback>
          <a-input placeholder="请输入权重" v-decorator="['topValue', {rules: [{required: true, message: '请输入权重!'}]}]" />
        </a-form-item>
        <a-form-item label="是否新窗口打开" :labelCol="labelCol" :wrapperCol="wrapperCol">
          <a-radio-group placeholder="请选择是否新窗口打开"
            v-decorator="['isNewWindowOpen',{rules: [{ required: true, message: '请选择是否新窗口打开!' }]}]">
            <a-radio v-for="(item,index) in isNewWindowOpenData" :key="index" :value="item.code">{{ item.name }}
            </a-radio>
          </a-radio-group>
        </a-form-item>
      </a-form>
    </a-spin>
  </a-modal>
</template>
<script>
  import {
    blogFriendshipLinkAdd
  } from '@/api/modular/main/blogfriendshiplink/blogFriendshipLinkManage'
  export default {
    data() {
      return {
        labelCol: {
          xs: {
            span: 24
          },
          sm: {
            span: 5
          }
        },
        wrapperCol: {
          xs: {
            span: 24
          },
          sm: {
            span: 15
          }
        },
        linkTypeData: [],
        isNewWindowOpenData: [],
        visible: false,
        confirmLoading: false,
        form: this.$form.createForm(this)
      }
    },
    methods: {
      // 初始化方法
      add(record) {
        this.visible = true
        const linkTypeOption = this.$options
        this.linkTypeData = linkTypeOption.filters['dictData']('blog_link_type')
        const isNewWindowOpenOption = this.$options
        this.isNewWindowOpenData = isNewWindowOpenOption.filters['dictData']('blog_yes_or_no')
      },
      /**
       * 提交表单
       */
      handleSubmit() {
        const {
          form: {
            validateFields
          }
        } = this
        this.confirmLoading = true
        validateFields((errors, values) => {
          if (!errors) {
            for (const key in values) {
              if (typeof(values[key]) === 'object' && values[key] != null) {
                values[key] = JSON.stringify(values[key])
              }
            }
            blogFriendshipLinkAdd(values).then((res) => {
              if (res.success) {
                this.$message.success('新增成功')
                this.confirmLoading = false
                this.$emit('ok', values)
                this.handleCancel()
              } else {
                this.$message.error('新增失败') // + res.message
              }
            }).finally((res) => {
              this.confirmLoading = false
            })
          } else {
            this.confirmLoading = false
          }
        })
      },
      handleCancel() {
        this.form.resetFields()
        this.visible = false
      }
    }
  }
</script>
_web/src/views/main/blogfriendshiplink/editForm.vue
New file
@@ -0,0 +1,140 @@
<template>
  <a-modal title="编辑友情链接" :width="900" :visible="visible" :confirmLoading="confirmLoading" @ok="handleSubmit"
    @cancel="handleCancel">
    <a-spin :spinning="confirmLoading">
      <a-form :form="form">
        <a-form-item v-show="false">
          <a-input v-decorator="['id']" />
        </a-form-item>
        <a-form-item label="名称" :labelCol="labelCol" :wrapperCol="wrapperCol" has-feedback>
          <a-input placeholder="请输入名称" v-decorator="['name', {rules: [{required: true, message: '请输入名称!'}]}]" />
        </a-form-item>
        <a-form-item label="url地址" :labelCol="labelCol" :wrapperCol="wrapperCol" has-feedback>
          <a-input placeholder="请输入url地址" v-decorator="['url', {rules: [{required: true, message: '请输入url地址!'}]}]" />
        </a-form-item>
        <a-form-item label="头像地址" :labelCol="labelCol" :wrapperCol="wrapperCol" has-feedback>
          <a-input placeholder="请输入头像地址" v-decorator="['avatar', {rules: [{required: false, message: '请输入头像地址!'}]}]" />
        </a-form-item>
        <a-form-item label="描述" :labelCol="labelCol" :wrapperCol="wrapperCol" has-feedback>
          <a-input placeholder="请输入描述" v-decorator="['remark', {rules: [{required: true, message: '请输入描述!'}]}]" />
        </a-form-item>
        <a-form-item label="链接类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
          <a-radio-group placeholder="请选择链接类型"
            v-decorator="['linkType',{rules: [{ required: true, message: '请选择链接类型!' }]}]">
            <a-radio v-for="(item,index) in linkTypeData" :key="index" :value="item.code">{{ item.name }}</a-radio>
          </a-radio-group>
        </a-form-item>
        <a-form-item label="权重" :labelCol="labelCol" :wrapperCol="wrapperCol" has-feedback>
          <a-input placeholder="请输入权重" v-decorator="['topValue', {rules: [{required: true, message: '请输入权重!'}]}]" />
        </a-form-item>
        <a-form-item label="是否新窗口打开" :labelCol="labelCol" :wrapperCol="wrapperCol">
          <a-radio-group placeholder="请选择是否新窗口打开"
            v-decorator="['isNewWindowOpen',{rules: [{ required: true, message: '请选择是否新窗口打开!' }]}]">
            <a-radio v-for="(item,index) in isNewWindowOpenData" :key="index" :value="item.code">{{ item.name }}
            </a-radio>
          </a-radio-group>
        </a-form-item>
        <a-form-item label="是否启用" :labelCol="labelCol" :wrapperCol="wrapperCol">
          <a-radio-group placeholder="请选择是否启用"
            v-decorator="['isEnable',{rules: [{ required: true, message: '请选择是否启用!' }]}]">
            <a-radio v-for="(item,index) in isEnableData" :key="index" :value="item.code">{{ item.name }}</a-radio>
          </a-radio-group>
        </a-form-item>
      </a-form>
    </a-spin>
  </a-modal>
</template>
<script>
  import {
    blogFriendshipLinkEdit
  } from '@/api/modular/main/blogfriendshiplink/blogFriendshipLinkManage'
  export default {
    data() {
      return {
        labelCol: {
          xs: {
            span: 24
          },
          sm: {
            span: 5
          }
        },
        wrapperCol: {
          xs: {
            span: 24
          },
          sm: {
            span: 15
          }
        },
        linkTypeData: [],
        isEnableData: [],
        isNewWindowOpenData: [],
        visible: false,
        confirmLoading: false,
        form: this.$form.createForm(this)
      }
    },
    methods: {
      // 初始化方法
      edit(record) {
        this.visible = true
        const linkTypeOption = this.$options
        this.linkTypeData = linkTypeOption.filters['dictData']('blog_link_type')
        const isNewWindowOpenOption = this.$options
        this.isNewWindowOpenData = isNewWindowOpenOption.filters['dictData']('blog_yes_or_no')
        const isEnableOption = this.$options
        this.isEnableData = isEnableOption.filters['dictData']('blog_yes_or_no')
        setTimeout(() => {
          this.form.setFieldsValue({
            id: record.id,
            name: record.name,
            url: record.url,
            avatar: record.avatar,
            isEnable: record.isEnable,
            remark: record.remark,
            linkType: record.linkType,
            topValue: record.topValue,
            isNewWindowOpen: record.isNewWindowOpen
          })
        }, 100)
      },
      handleSubmit() {
        const {
          form: {
            validateFields
          }
        } = this
        this.confirmLoading = true
        validateFields((errors, values) => {
          if (!errors) {
            for (const key in values) {
              if (typeof(values[key]) === 'object' && values[key] != null) {
                values[key] = JSON.stringify(values[key])
              }
            }
            blogFriendshipLinkEdit(values).then((res) => {
              if (res.success) {
                this.$message.success('编辑成功')
                this.confirmLoading = false
                this.$emit('ok', values)
                this.handleCancel()
              } else {
                this.$message.error('编辑失败') //  + res.message
              }
            }).finally((res) => {
              this.confirmLoading = false
            })
          } else {
            this.confirmLoading = false
          }
        })
      },
      handleCancel() {
        this.form.resetFields()
        this.visible = false
      }
    }
  }
</script>
_web/src/views/main/blogfriendshiplink/index.vue
New file
@@ -0,0 +1,309 @@
<template>
  <div>
    <a-card :bordered="false" :bodyStyle="tstyle">
      <div class="table-page-search-wrapper" v-if="hasPerm('blogFriendshipLink:page')">
        <a-form layout="inline">
          <a-row :gutter="48">
            <a-col :md="8" :sm="24">
              <a-form-item label="名称">
                <a-input v-model="queryParam.name" allow-clear placeholder="请输入名称" />
              </a-form-item>
            </a-col>
            <a-col :md="8" :sm="24">
              <a-form-item label="链接类型">
                <a-select style="width: 100%" v-model="queryParam.linkType" placeholder="请选择链接类型">
                  <a-select-option v-for="(item,index) in linkTypeData" :key="index" :value="item.code">{{ item.name }}
                  </a-select-option>
                </a-select>
              </a-form-item>
            </a-col>
            <template v-if="advanced">
              <a-col :md="8" :sm="24">
                <a-form-item label="权重">
                  <a-input v-model="queryParam.topValue" allow-clear placeholder="请输入权重" />
                </a-form-item>
              </a-col>
              <a-col :md="8" :sm="24">
                <a-form-item label="是否启用">
                  <a-input v-model="queryParam.isEnable" allow-clear placeholder="请输入是否启用" />
                </a-form-item>
              </a-col>
              <a-col :md="8" :sm="24">
                <a-form-item label="是否新窗口打开">
                  <a-select style="width: 100%" v-model="queryParam.isNewWindowOpen" placeholder="请选择是否新窗口打开">
                    <a-select-option v-for="(item,index) in isNewWindowOpenData" :key="index" :value="item.code">
                      {{ item.name }}</a-select-option>
                  </a-select>
                </a-form-item>
              </a-col>
              <a-col :md="8" :sm="24">
                <a-form-item label="创建时间">
                  <a-date-picker style="width: 100%" placeholder="请选择创建时间" v-model="queryParam.createDateDate"
                    @change="onChangecreateDate" />
                </a-form-item>
              </a-col>
            </template>
            <a-col :md="8" :sm="24">
              <span class="table-page-search-submitButtons">
                <a-button type="primary" @click="$refs.table.refresh(true)">查询</a-button>
                <a-button style="margin-left: 8px" @click="() => queryParam = {}">重置</a-button>
                <a @click="toggleAdvanced" style="margin-left: 8px">
                  {{ advanced ? '收起' : '展开' }}
                  <a-icon :type="advanced ? 'up' : 'down'" />
                </a>
              </span>
            </a-col>
          </a-row>
        </a-form>
      </div>
    </a-card>
    <a-card :bordered="false">
      <s-table ref="table" :columns="columns" :data="loadData" :alert="options.alert" :rowKey="(record) => record.id"
        :rowSelection="options.rowSelection">
        <template class="table-operator" slot="operator" v-if="hasPerm('blogFriendshipLink:add')">
          <a-button type="primary" v-if="hasPerm('blogFriendshipLink:add')" icon="plus" @click="$refs.addForm.add()">
            新增友情链接</a-button>
          <a-button type="danger" :disabled="selectedRowKeys.length < 1" v-if="hasPerm('blogFriendshipLink:delete')"
            @click="batchDelete">
            <a-icon type="delete" />批量删除
          </a-button>
          <x-down v-if="hasPerm('blogFriendshipLink:export')" ref="batchExport" @batchExport="batchExport" />
        </template>
        <span slot="linkTypeScopedSlots" slot-scope="text">
          {{ 'blog_link_type' | dictType(text) }}
        </span>
        <span slot="isEnableScopedSlots" slot-scope="text">
          {{ 'blog_yes_or_no' | dictType(text) }}
        </span>
        <span slot="isNewWindowOpenScopedSlots" slot-scope="text">
          {{ 'blog_yes_or_no' | dictType(text) }}
        </span>
        <span slot="action" slot-scope="text, record">
          <a v-if="hasPerm('blogFriendshipLink:edit')" @click="$refs.editForm.edit(record)">编辑</a>
          <a-divider type="vertical" v-if="hasPerm('blogFriendshipLink:edit') & hasPerm('blogFriendshipLink:delete')" />
          <a-popconfirm v-if="hasPerm('blogFriendshipLink:delete')" placement="topRight" title="确认删除?"
            @confirm="() => singleDelete(record)">
            <a>删除</a>
          </a-popconfirm>
        </span>
      </s-table>
      <add-form ref="addForm" @ok="handleOk" />
      <edit-form ref="editForm" @ok="handleOk" />
    </a-card>
  </div>
</template>
<script>
  import {
    STable,
    XDown
  } from '@/components'
  import moment from 'moment'
  import {
    blogFriendshipLinkPage,
    blogFriendshipLinkDelete,
    blogFriendshipLinkExport
  } from '@/api/modular/main/blogfriendshiplink/blogFriendshipLinkManage'
  import addForm from './addForm.vue'
  import editForm from './editForm.vue'
  export default {
    components: {
      STable,
      addForm,
      editForm,
      XDown
    },
    data() {
      return {
        // 高级搜索 展开/关闭
        advanced: false,
        // 查询参数
        queryParam: {},
        // 表头
        columns: [{
            title: '名称',
            align: 'center',
            dataIndex: 'name'
          },
          {
            title: 'url地址',
            align: 'center',
            dataIndex: 'url'
          },
          {
            title: '头像地址',
            align: 'center',
            dataIndex: 'avatar'
          },
          {
            title: '描述',
            align: 'center',
            dataIndex: 'remark'
          },
          {
            title: '链接类型',
            align: 'center',
            dataIndex: 'linkType',
            scopedSlots: {
              customRender: 'linkTypeScopedSlots'
            }
          },
          {
            title: '权重',
            align: 'center',
            dataIndex: 'topValue'
          },
          {
            title: '是否启用',
            align: 'center',
            dataIndex: 'isEnable',
            scopedSlots: {
              customRender: 'isEnableScopedSlots'
            }
          },
          {
            title: '是否新窗口打开',
            align: 'center',
            dataIndex: 'isNewWindowOpen',
            scopedSlots: {
              customRender: 'isNewWindowOpenScopedSlots'
            }
          },
          {
            title: '更新时间',
            align: 'center',
            dataIndex: 'updateDate'
          },
          {
            title: '创建时间',
            align: 'center',
            dataIndex: 'createDate'
          }
        ],
        tstyle: {
          'padding-bottom': '0px',
          'margin-bottom': '10px'
        },
        // 加载数据方法 必须为 Promise 对象
        loadData: parameter => {
          return blogFriendshipLinkPage(Object.assign(parameter, this.switchingDate())).then((res) => {
            return res.data
          })
        },
        linkTypeData: [],
        isNewWindowOpenData: [],
        selectedRowKeys: [],
        selectedRows: [],
        options: {
          alert: {
            show: true,
            clear: () => {
              this.selectedRowKeys = []
            }
          },
          rowSelection: {
            selectedRowKeys: this.selectedRowKeys,
            onChange: this.onSelectChange
          }
        }
      }
    },
    created() {
      if (this.hasPerm('blogFriendshipLink:edit') || this.hasPerm('blogFriendshipLink:delete')) {
        this.columns.push({
          title: '操作',
          width: '150px',
          dataIndex: 'action',
          scopedSlots: {
            customRender: 'action'
          }
        })
      }
      const linkTypeOption = this.$options
      this.linkTypeData = linkTypeOption.filters['dictData']('blog_link_type')
      const isNewWindowOpenOption = this.$options
      this.isNewWindowOpenData = isNewWindowOpenOption.filters['dictData']('blog_yes_or_no')
    },
    methods: {
      moment,
      /**
       * 查询参数组装
       */
      switchingDate() {
        const queryParamcreateDate = this.queryParam.createDateDate
        if (queryParamcreateDate != null) {
          this.queryParam.createDate = moment(queryParamcreateDate).format('YYYY-MM-DD')
          if (queryParamcreateDate.length < 1) {
            delete this.queryParam.createDate
          }
        }
        const obj = JSON.parse(JSON.stringify(this.queryParam))
        return obj
      },
      /**
       * 单个删除
       */
      singleDelete(record) {
        const param = [{
          'id': record.id
        }]
        this.blogFriendshipLinkDelete(param)
      },
      /**
       * 批量删除
       */
      batchDelete() {
        const paramIds = this.selectedRowKeys.map((d) => {
          return {
            'id': d
          }
        })
        this.blogFriendshipLinkDelete(paramIds)
      },
      blogFriendshipLinkDelete(record) {
        blogFriendshipLinkDelete(record).then((res) => {
          if (res.success) {
            this.$message.success('删除成功')
            this.$refs.table.clearRefreshSelected()
          } else {
            this.$message.error('删除失败') // + res.message
          }
        })
      },
      toggleAdvanced() {
        this.advanced = !this.advanced
      },
      onChangecreateDate(date, dateString) {
        this.createDateDateString = dateString
      },
      /**
       * 批量导出
       */
      batchExport() {
        const paramIds = this.selectedRowKeys.map((d) => {
          return {
            'id': d
          }
        })
        blogFriendshipLinkExport(paramIds).then((res) => {
          this.$refs.batchExport.downloadfile(res)
        })
      },
      handleOk() {
        this.$refs.table.refresh()
      },
      onSelectChange(selectedRowKeys, selectedRows) {
        this.selectedRowKeys = selectedRowKeys
        this.selectedRows = selectedRows
      }
    }
  }
</script>
<style lang="less">
  .table-operator {
    margin-bottom: 18px;
  }
  button {
    margin-right: 8px;
  }
</style>
snowy-main/src/main/java/vip/xiaonuo/modular/blogStatistics/BlogStatisticsController.java
@@ -63,21 +63,17 @@
    @BusinessLog(title = "外部blog系统_统计_查询", opType = LogAnnotionOpTypeEnum.QUERY)
    public ResponseData statistics() {
        //相差一个月,31天
        long betweenDay = DateUtil.between(DateUtil.parseDate("2020-05-27"), new Date(), DateUnit.DAY);
        String updateDate;
        BlogArticle lastUpdateBlog = blogArticleService.lambdaQuery().orderByDesc(BlogArticle::getUpdateDate)
                .last(" limit 1 ").one();
        String updateDate = "--";
        BlogArticle lastUpdateBlog = blogArticleService.lambdaQuery().orderByDesc(BlogArticle::getUpdateDate).last(" limit 1 ").one();
        if (lastUpdateBlog != null && lastUpdateBlog.getUpdateDate() != null) {
            updateDate = DateUtil.formatDate(lastUpdateBlog.getUpdateDate());
        } else {
            updateDate = "--";
        }
        String startFrom = "从这开始: 2020-05-27 ";
        String aliveDayCount = "已稳定运行:" + betweenDay + "天";
        String aliveDayCount = "已稳定运行:" + DateUtil.between(DateUtil.parseDate("2022-02-14"), new Date(), DateUnit.DAY) + "天";
        String lastUpdateDate = "上次更新:" + updateDate;
        String visitCount = "累计访问:1010次";
        String visitorCount = "累计访客:1001名";
        String visitCount = "累计访问:1010次"; //24小时ip 访问次数
        String visitorCount = "累计访客:1001名";//所有时间ip个数
        List<BlogStatisticsVo.simpleVo> res = new ArrayList<>();
        res.add(new BlogStatisticsVo.simpleVo().setName(startFrom));
snowy-main/src/main/java/vip/xiaonuo/modular/blogarticle/entity/BlogArticle.java
@@ -25,9 +25,7 @@
package vip.xiaonuo.modular.blogarticle.entity;
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.util.Date;
@@ -154,12 +152,14 @@
     * 更新时间
     */
    @Excel(name = "更新时间", databaseFormat = "yyyy-MM-dd HH:mm:ss", format = "yyyy-MM-dd", width = 20)
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateDate;
    /**
     * 创建时间
     */
    @Excel(name = "创建时间", databaseFormat = "yyyy-MM-dd HH:mm:ss", format = "yyyy-MM-dd", width = 20)
    @TableField(fill = FieldFill.INSERT)
    private Date createDate;
}
snowy-main/src/main/java/vip/xiaonuo/modular/blogarticletype/controller/BlogArticleTypeOutsideController.java
File was renamed from snowy-main/src/main/java/vip/xiaonuo/modular/blogarticletype/controller/BlogArticleTypeOutSideController.java
@@ -49,7 +49,7 @@
 */
@RestController
@RequestMapping("/outside")
public class BlogArticleTypeOutSideController {
public class BlogArticleTypeOutsideController {
    @Resource
    private BlogArticleTypeService blogArticleTypeService;
@@ -75,6 +75,7 @@
                    return vo;
                }).collect(Collectors.toList());
        return new SuccessResponseData(list);
    }
}
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/controller/BlogFriendshipLinkController.java
New file
@@ -0,0 +1,148 @@
/*
Copyright [2020] [https://www.xiaonuo.vip]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处,作者声明等。
4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点,可申请商业授权,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.blogfriendshiplink.controller;
import vip.xiaonuo.core.annotion.BusinessLog;
import vip.xiaonuo.core.annotion.Permission;
import vip.xiaonuo.core.enums.LogAnnotionOpTypeEnum;
import vip.xiaonuo.core.pojo.response.ResponseData;
import vip.xiaonuo.core.pojo.response.SuccessResponseData;
import vip.xiaonuo.modular.blogfriendshiplink.param.BlogFriendshipLinkParam;
import vip.xiaonuo.modular.blogfriendshiplink.service.BlogFriendshipLinkService;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import javax.annotation.Resource;
import java.util.List;
/**
 * 友情链接控制器
 *
 * @author inleft
 * @date 2022-02-17 15:05:44
 */
@RestController
public class BlogFriendshipLinkController {
    @Resource
    private BlogFriendshipLinkService blogFriendshipLinkService;
    /**
     * 查询友情链接
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
    @Permission
    @GetMapping("/blogFriendshipLink/page")
    @BusinessLog(title = "友情链接_查询", opType = LogAnnotionOpTypeEnum.QUERY)
    public ResponseData page(BlogFriendshipLinkParam blogFriendshipLinkParam) {
        return new SuccessResponseData(blogFriendshipLinkService.page(blogFriendshipLinkParam));
    }
    /**
     * 添加友情链接
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
    @Permission
    @PostMapping("/blogFriendshipLink/add")
    @BusinessLog(title = "友情链接_增加", opType = LogAnnotionOpTypeEnum.ADD)
    public ResponseData add(@RequestBody @Validated(BlogFriendshipLinkParam.add.class) BlogFriendshipLinkParam blogFriendshipLinkParam) {
            blogFriendshipLinkService.add(blogFriendshipLinkParam);
        return new SuccessResponseData();
    }
    /**
     * 删除友情链接,可批量删除
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
    @Permission
    @PostMapping("/blogFriendshipLink/delete")
    @BusinessLog(title = "友情链接_删除", opType = LogAnnotionOpTypeEnum.DELETE)
    public ResponseData delete(@RequestBody @Validated(BlogFriendshipLinkParam.delete.class) List<BlogFriendshipLinkParam> blogFriendshipLinkParamList) {
            blogFriendshipLinkService.delete(blogFriendshipLinkParamList);
        return new SuccessResponseData();
    }
    /**
     * 编辑友情链接
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
    @Permission
    @PostMapping("/blogFriendshipLink/edit")
    @BusinessLog(title = "友情链接_编辑", opType = LogAnnotionOpTypeEnum.EDIT)
    public ResponseData edit(@RequestBody @Validated(BlogFriendshipLinkParam.edit.class) BlogFriendshipLinkParam blogFriendshipLinkParam) {
            blogFriendshipLinkService.edit(blogFriendshipLinkParam);
        return new SuccessResponseData();
    }
    /**
     * 查看友情链接
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
    @Permission
    @GetMapping("/blogFriendshipLink/detail")
    @BusinessLog(title = "友情链接_查看", opType = LogAnnotionOpTypeEnum.DETAIL)
    public ResponseData detail(@Validated(BlogFriendshipLinkParam.detail.class) BlogFriendshipLinkParam blogFriendshipLinkParam) {
        return new SuccessResponseData(blogFriendshipLinkService.detail(blogFriendshipLinkParam));
    }
    /**
     * 友情链接列表
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
    @Permission
    @GetMapping("/blogFriendshipLink/list")
    @BusinessLog(title = "友情链接_列表", opType = LogAnnotionOpTypeEnum.QUERY)
    public ResponseData list(BlogFriendshipLinkParam blogFriendshipLinkParam) {
        return new SuccessResponseData(blogFriendshipLinkService.list(blogFriendshipLinkParam));
    }
    /**
     * 导出系统用户
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
    @Permission
    @GetMapping("/blogFriendshipLink/export")
    @BusinessLog(title = "友情链接_导出", opType = LogAnnotionOpTypeEnum.EXPORT)
    public void export(BlogFriendshipLinkParam blogFriendshipLinkParam) {
        blogFriendshipLinkService.export(blogFriendshipLinkParam);
    }
}
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/controller/BlogLinkOutsideController.java
New file
@@ -0,0 +1,112 @@
/*
Copyright [2020] [https://www.xiaonuo.vip]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处,作者声明等。
4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点,可申请商业授权,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.blogfriendshiplink.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Dict;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import vip.xiaonuo.core.annotion.BusinessLog;
import vip.xiaonuo.core.consts.CommonConstant;
import vip.xiaonuo.core.consts.MyConstant;
import vip.xiaonuo.core.enums.LogAnnotionOpTypeEnum;
import vip.xiaonuo.core.pojo.response.ResponseData;
import vip.xiaonuo.core.pojo.response.SuccessResponseData;
import vip.xiaonuo.modular.blogfriendshiplink.entity.BlogFriendshipLink;
import vip.xiaonuo.modular.blogfriendshiplink.param.BlogFriendshipLinkVo;
import vip.xiaonuo.modular.blogfriendshiplink.param.BlogLinkVo;
import vip.xiaonuo.modular.blogfriendshiplink.service.BlogFriendshipLinkService;
import vip.xiaonuo.sys.modular.dict.param.SysDictTypeParam;
import vip.xiaonuo.sys.modular.dict.service.SysDictTypeService;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
 * 友情链接 控制器
 *
 * @author inleft
 * @date 2022-02-15 15:17:15
 */
@RestController
@RequestMapping("/outside")
public class BlogLinkOutsideController {
    @Resource
    private BlogFriendshipLinkService blogFriendshipLinkService;
    @Resource
    private SysDictTypeService sysDictTypeService;
    /**
     * 查询blog友情链接
     *
     * @author inleft
     * @date 2022-02-09 18:20:22
     */
    @GetMapping("/blogLink/queryBlogLinkGroup")
    @BusinessLog(title = "外部blog系统_blog友情链接组_查询", opType = LogAnnotionOpTypeEnum.QUERY)
    public ResponseData queryBlogLinkGroup() {
        List<BlogFriendshipLink> linkList = blogFriendshipLinkService.lambdaQuery()
                .eq(BlogFriendshipLink::getIsEnable,MyConstant.Yes)
                .orderByAsc(BlogFriendshipLink::getTopValue)
                .orderByAsc(BlogFriendshipLink::getName)
                .list();
        Map<String, List<BlogFriendshipLink>> groupLink = linkList.stream()
                .collect(Collectors.groupingBy(e -> e.getLinkType().toString(), LinkedHashMap::new, Collectors.mapping(Function.identity(),
                        Collectors.toList())));
        SysDictTypeParam param = new SysDictTypeParam();
        param.setCode("blog_link_type");
        List<Dict> dictList = sysDictTypeService.dropDown(param);
        List<BlogLinkVo> res = new ArrayList<>(dictList.size());
        List<BlogFriendshipLink> tempLink;
        BlogLinkVo vo;
        for (Dict dict : dictList) {
            if ((tempLink = groupLink.get(dict.get(CommonConstant.CODE))) != null) {
                vo = new BlogLinkVo();
                vo.setGroupName(dict.get(CommonConstant.VALUE).toString());
                vo.setLinkVoList(tempLink.stream().map(e -> {
                    BlogFriendshipLinkVo tempLinkVo = new BlogFriendshipLinkVo();
                    BeanUtil.copyProperties(e, tempLinkVo);
                    return tempLinkVo;
                }).collect(Collectors.toList()));
                res.add(vo);
            }
        }
        return new SuccessResponseData(res);
    }
}
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/entity/BlogFriendshipLink.java
New file
@@ -0,0 +1,111 @@
/*
Copyright [2020] [https://www.xiaonuo.vip]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处,作者声明等。
4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点,可申请商业授权,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.blogfriendshiplink.entity;
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.util.Date;
/**
 * 友情链接
 *
 * @author inleft
 * @date 2022-02-17 15:05:44
 */
@Data
@TableName("blog_friendship_link")
public class BlogFriendshipLink {
    /**
     * 自增id
     */
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    /**
     * 名称
     */
    @Excel(name = "名称")
    private String name;
    /**
     * url地址
     */
    @Excel(name = "url地址")
    private String url;
    /**
     * 头像地址
     */
    @Excel(name = "头像地址")
    private String avatar;
    /**
     * 描述
     */
    @Excel(name = "描述")
    private String remark;
    /**
     * 链接类型
     */
    @Excel(name = "链接类型")
    private Integer linkType;
    /**
     * 权重
     */
    @Excel(name = "权重")
    private Integer topValue;
    /**
     * 是否启用
     */
    @Excel(name = "是否启用")
    private Integer isEnable;
    /**
     * 是否新窗口打开
     */
    @Excel(name = "是否新窗口打开")
    private Integer isNewWindowOpen;
    /**
     * 更新时间
     */
    @Excel(name = "更新时间", databaseFormat = "yyyy-MM-dd HH:mm:ss", format = "yyyy-MM-dd", width = 20)
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateDate;
    /**
     * 创建时间
     */
    @Excel(name = "创建时间", databaseFormat = "yyyy-MM-dd HH:mm:ss", format = "yyyy-MM-dd", width = 20)
    @TableField(fill = FieldFill.INSERT)
    private Date createDate;
}
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/enums/BlogFriendshipLinkExceptionEnum.java
New file
@@ -0,0 +1,64 @@
/*
Copyright [2020] [https://www.xiaonuo.vip]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处,作者声明等。
4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点,可申请商业授权,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.blogfriendshiplink.enums;
import vip.xiaonuo.core.annotion.ExpEnumType;
import vip.xiaonuo.core.exception.enums.abs.AbstractBaseExceptionEnum;
import vip.xiaonuo.core.factory.ExpEnumCodeFactory;
import vip.xiaonuo.sys.core.consts.SysExpEnumConstant;
/**
 * 友情链接
 *
 * @author inleft
 * @date 2022-02-17 15:05:44
 */
@ExpEnumType(module = SysExpEnumConstant.SNOWY_SYS_MODULE_EXP_CODE)
public enum BlogFriendshipLinkExceptionEnum implements AbstractBaseExceptionEnum {
    /**
     * 数据不存在
     */
    NOT_EXIST(1, "此数据不存在");
    private final Integer code;
    private final String message;
        BlogFriendshipLinkExceptionEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
    @Override
    public Integer getCode() {
        return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
    }
    @Override
    public String getMessage() {
        return message;
    }
}
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/mapper/BlogFriendshipLinkMapper.java
New file
@@ -0,0 +1,37 @@
/*
Copyright [2020] [https://www.xiaonuo.vip]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处,作者声明等。
4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点,可申请商业授权,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.blogfriendshiplink.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import vip.xiaonuo.modular.blogfriendshiplink.entity.BlogFriendshipLink;
/**
 * 友情链接
 *
 * @author inleft
 * @date 2022-02-17 15:05:44
 */
public interface BlogFriendshipLinkMapper extends BaseMapper<BlogFriendshipLink> {
}
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/mapper/mapping/BlogFriendshipLinkMapper.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="vip.xiaonuo.modular.blogfriendshiplink.mapper.BlogFriendshipLinkMapper">
</mapper>
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/param/BlogFriendshipLinkParam.java
New file
@@ -0,0 +1,104 @@
/*
Copyright [2020] [https://www.xiaonuo.vip]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处,作者声明等。
4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点,可申请商业授权,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.blogfriendshiplink.param;
import lombok.Data;
import vip.xiaonuo.core.pojo.base.param.BaseParam;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 友情链接参数类
 *
 * @author inleft
 * @date 2022-02-17 15:05:44
*/
@Data
public class BlogFriendshipLinkParam extends BaseParam {
    /**
     * 自增id
     */
    @NotNull(message = "自增id不能为空,请检查id参数", groups = {edit.class, delete.class, detail.class})
    private Long id;
    /**
     * 名称
     */
    @NotBlank(message = "名称不能为空,请检查name参数", groups = {add.class, edit.class})
    private String name;
    /**
     * url地址
     */
    @NotBlank(message = "url地址不能为空,请检查url参数", groups = {add.class, edit.class})
    private String url;
    /**
     * 头像地址
     */
    private String avatar;
    /**
     * 描述
     */
    //@NotBlank(message = "描述不能为空,请检查remark参数", groups = {add.class, edit.class})
    private String remark;
    /**
     * 链接类型
     */
    @NotNull(message = "链接类型不能为空,请检查linkType参数", groups = {add.class, edit.class})
    private Integer linkType;
    /**
     * 权重
     */
    @NotNull(message = "权重不能为空,请检查topValue参数", groups = {add.class, edit.class})
    private Integer topValue;
    /**
     * 是否启用
     */
    private Integer isEnable;
    /**
     * 是否新窗口打开
     */
    @NotNull(message = "是否新窗口打开不能为空,请检查isNewWindowOpen参数", groups = {add.class, edit.class})
    private Integer isNewWindowOpen;
    /**
     * 更新时间
     */
    private String updateDate;
    /**
     * 创建时间
     */
    private String createDate;
}
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/param/BlogFriendshipLinkVo.java
New file
@@ -0,0 +1,76 @@
/*
Copyright [2020] [https://www.xiaonuo.vip]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处,作者声明等。
4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点,可申请商业授权,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.blogfriendshiplink.param;
import lombok.Data;
/**
 * 友情链接
 *
 * @author inleft
 * @date 2022-02-17 15:05:44
 */
@Data
public class BlogFriendshipLinkVo {
    /**
     * 自增id
     */
    private Long id;
    /**
     * 名称
     */
    private String name;
    /**
     * url地址
     */
    private String url;
    /**
     * 头像地址
     */
    private String avatar;
    /**
     * 描述
     */
    private String remark;
    /**
     * 链接类型
     */
    private Integer linkType;
    /**
     * 是否新窗口打开
     */
    private Integer isNewWindowOpen;
}
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/param/BlogLinkVo.java
New file
@@ -0,0 +1,45 @@
/*
Copyright [2020] [https://www.xiaonuo.vip]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处,作者声明等。
4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点,可申请商业授权,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.blogfriendshiplink.param;
import lombok.Data;
import java.util.List;
/**
 * 友情链接参数类
 *
 * @author inleft
 * @date 2022-02-17 15:05:44
 */
@Data
public class BlogLinkVo {
    private String groupName;
    private List<BlogFriendshipLinkVo> linkVoList;
}
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/service/BlogFriendshipLinkService.java
New file
@@ -0,0 +1,97 @@
/*
Copyright [2020] [https://www.xiaonuo.vip]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处,作者声明等。
4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点,可申请商业授权,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.blogfriendshiplink.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vip.xiaonuo.core.pojo.page.PageResult;
import vip.xiaonuo.modular.blogfriendshiplink.entity.BlogFriendshipLink;
import vip.xiaonuo.modular.blogfriendshiplink.param.BlogFriendshipLinkParam;
import java.util.List;
/**
 * 友情链接service接口
 *
 * @author inleft
 * @date 2022-02-17 15:05:44
 */
public interface BlogFriendshipLinkService extends IService<BlogFriendshipLink> {
    /**
     * 查询友情链接
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
    PageResult<BlogFriendshipLink> page(BlogFriendshipLinkParam blogFriendshipLinkParam);
    /**
     * 友情链接列表
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
    List<BlogFriendshipLink> list(BlogFriendshipLinkParam blogFriendshipLinkParam);
    /**
     * 添加友情链接
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
    void add(BlogFriendshipLinkParam blogFriendshipLinkParam);
    /**
     * 删除友情链接
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
    void delete(List<BlogFriendshipLinkParam> blogFriendshipLinkParamList);
    /**
     * 编辑友情链接
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
    void edit(BlogFriendshipLinkParam blogFriendshipLinkParam);
    /**
     * 查看友情链接
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
     BlogFriendshipLink detail(BlogFriendshipLinkParam blogFriendshipLinkParam);
    /**
     * 导出友情链接
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
     void export(BlogFriendshipLinkParam blogFriendshipLinkParam);
}
snowy-main/src/main/java/vip/xiaonuo/modular/blogfriendshiplink/service/impl/BlogFriendshipLinkServiceImpl.java
New file
@@ -0,0 +1,140 @@
/*
Copyright [2020] [https://www.xiaonuo.vip]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处,作者声明等。
4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点,可申请商业授权,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.blogfriendshiplink.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.factory.PageFactory;
import vip.xiaonuo.core.pojo.page.PageResult;
import vip.xiaonuo.core.util.PoiUtil;
import vip.xiaonuo.modular.blogfriendshiplink.entity.BlogFriendshipLink;
import vip.xiaonuo.modular.blogfriendshiplink.enums.BlogFriendshipLinkExceptionEnum;
import vip.xiaonuo.modular.blogfriendshiplink.mapper.BlogFriendshipLinkMapper;
import vip.xiaonuo.modular.blogfriendshiplink.param.BlogFriendshipLinkParam;
import vip.xiaonuo.modular.blogfriendshiplink.service.BlogFriendshipLinkService;
import java.util.List;
/**
 * 友情链接service接口实现类
 *
 * @author inleft
 * @date 2022-02-17 15:05:44
 */
@Service
public class BlogFriendshipLinkServiceImpl extends ServiceImpl<BlogFriendshipLinkMapper, BlogFriendshipLink> implements BlogFriendshipLinkService {
    @Override
    public PageResult<BlogFriendshipLink> page(BlogFriendshipLinkParam blogFriendshipLinkParam) {
        QueryWrapper<BlogFriendshipLink> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(blogFriendshipLinkParam)) {
            // 根据名称 查询
            if (ObjectUtil.isNotEmpty(blogFriendshipLinkParam.getName())) {
                queryWrapper.lambda().like(BlogFriendshipLink::getName, blogFriendshipLinkParam.getName());
            }
            // 根据链接类型 查询
            if (ObjectUtil.isNotEmpty(blogFriendshipLinkParam.getLinkType())) {
                queryWrapper.lambda().eq(BlogFriendshipLink::getLinkType, blogFriendshipLinkParam.getLinkType());
            }
            // 根据权重 查询
            if (ObjectUtil.isNotEmpty(blogFriendshipLinkParam.getTopValue())) {
                queryWrapper.lambda().eq(BlogFriendshipLink::getTopValue, blogFriendshipLinkParam.getTopValue());
            }
            // 根据是否启用 查询
            if (ObjectUtil.isNotEmpty(blogFriendshipLinkParam.getIsEnable())) {
                queryWrapper.lambda().eq(BlogFriendshipLink::getIsEnable, blogFriendshipLinkParam.getIsEnable());
            }
            // 根据是否新窗口打开 查询
            if (ObjectUtil.isNotEmpty(blogFriendshipLinkParam.getIsNewWindowOpen())) {
                queryWrapper.lambda().eq(BlogFriendshipLink::getIsNewWindowOpen, blogFriendshipLinkParam.getIsNewWindowOpen());
            }
            // 根据创建时间 查询
            if (ObjectUtil.isNotEmpty(blogFriendshipLinkParam.getCreateDate())) {
                queryWrapper.lambda().eq(BlogFriendshipLink::getCreateDate, blogFriendshipLinkParam.getCreateDate());
            }
        }
        return new PageResult<>(this.page(PageFactory.defaultPage(), queryWrapper));
    }
    @Override
    public List<BlogFriendshipLink> list(BlogFriendshipLinkParam blogFriendshipLinkParam) {
        return this.list();
    }
    @Override
    public void add(BlogFriendshipLinkParam blogFriendshipLinkParam) {
        BlogFriendshipLink blogFriendshipLink = new BlogFriendshipLink();
        BeanUtil.copyProperties(blogFriendshipLinkParam, blogFriendshipLink);
        this.save(blogFriendshipLink);
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<BlogFriendshipLinkParam> blogFriendshipLinkParamList) {
        blogFriendshipLinkParamList.forEach(blogFriendshipLinkParam -> {
            this.removeById(blogFriendshipLinkParam.getId());
        });
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(BlogFriendshipLinkParam blogFriendshipLinkParam) {
        BlogFriendshipLink blogFriendshipLink = this.queryBlogFriendshipLink(blogFriendshipLinkParam);
        BeanUtil.copyProperties(blogFriendshipLinkParam, blogFriendshipLink);
        this.updateById(blogFriendshipLink);
    }
    @Override
    public BlogFriendshipLink detail(BlogFriendshipLinkParam blogFriendshipLinkParam) {
        return this.queryBlogFriendshipLink(blogFriendshipLinkParam);
    }
    /**
     * 获取友情链接
     *
     * @author inleft
     * @date 2022-02-17 15:05:44
     */
    private BlogFriendshipLink queryBlogFriendshipLink(BlogFriendshipLinkParam blogFriendshipLinkParam) {
        BlogFriendshipLink blogFriendshipLink = this.getById(blogFriendshipLinkParam.getId());
        if (ObjectUtil.isNull(blogFriendshipLink)) {
            throw new ServiceException(BlogFriendshipLinkExceptionEnum.NOT_EXIST);
        }
        return blogFriendshipLink;
    }
    @Override
    public void export(BlogFriendshipLinkParam blogFriendshipLinkParam) {
        List<BlogFriendshipLink> list = this.list(blogFriendshipLinkParam);
        PoiUtil.exportExcelWithStream("SnowyBlogFriendshipLink.xls", BlogFriendshipLink.class, list);
    }
}
snowy-main/src/main/resources/application-local.yml
@@ -13,6 +13,11 @@
    port: 6379
    password: mpw:xMwjz92TmxCDCJYvcfwIZA==
mybatis-plus:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# Oracle数据库
#spring:
#  datasource:
snowy-main/src/main/resources/application-prod.yml
@@ -1,14 +1,16 @@
JwtAuthenticationTokenFilter# Mysql数据库
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/snowy-pub?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=CTT&nullCatalogMeansCurrent=true
    username: root
    password: 123456
    url: mpw:pOR3O+UltK0HTNqvX/MeDsJDOCUeDoAnP5TsPqREtj384CDziueYbj8Z0bha3LWM1LdIKYTQuyS9cEaTceRHtJQIZymWMwsKEV++JDZgqBVnx9B5ztb3dGk3IhB678/E/rH1lJ8Jpzw21EkgPcie3A6ELU62rlJUycpcnK95oBDXKYZeMclnNdMVH5PVP70z5cWc5Ai741/1a/doxqo92IFnBMMyJG+r4B7KXBf3/LMm6xpvUm6e4xYPzpoy4hhNFp4TfNBWcsO0BEMH1GJaMw==
    username: mpw:Zr3vDuEdTm3NPpydFgU2eA==
    password: mpw:KWYe3LgV6I2rToYRn3k35g==
#    url: jdbc:mysql://localhost:3306/blog?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=CTT&nullCatalogMeansCurrent=true
#    username: root
#    password: root
  redis:
    host: localhost
    host: mpw:74taZBJwkaUlVuljmdqsRg==
    port: 6379
    password:
    password: mpw:xMwjz92TmxCDCJYvcfwIZA==
# Oracle数据库
#spring:
snowy-main/src/main/resources/application.yml
@@ -27,8 +27,7 @@
    cache-enabled: true
    lazy-loading-enabled: true
    multiple-result-sets-enabled: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#    log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
    log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
  global-config:
    banner: false
    db-config: