练手项目2笔记之day03

1. 自定义条件查询

1. 需求分析

在页面输入查询条件,查询符合条件的页面信息

查询条件如下:

站点id:精确匹配

模板id:精确匹配

页面别名:模糊匹配

2. 服务端

1. dao

还是用CmsPageRepository的findAll()方法,参数多了Example,无需定义

测试findAll方法实现自定义条件查询

@Test
public void testFindAllByExample(){

  // 分页参数
  int page = 0;
  int size = 10;
  Pageable pageable = PageRequest.of(page,size);

  // 条件值对象
  CmsPage cmsPage = new CmsPage();
  //        cmsPage.setSiteId("5a751fab6abb5044e0d19ea1");
  cmsPage.setPageAliase("轮播");
  // 条件匹配器
  ExampleMatcher exampleMatcher = ExampleMatcher.matching();
  exampleMatcher = exampleMatcher.withMatcher("pageAliase", ExampleMatcher.GenericPropertyMatchers.contains());
  // 定义example
  Example<CmsPage> example = Example.of(cmsPage,exampleMatcher);
  Page<CmsPage> all = cmsPageRepository.findAll(example, pageable);
  List<CmsPage> content = all.getContent();
  System.out.println(content);
}
2. Service

在PageService的findlist方法中增加自定义条件查询代码

public QueryResponseResult findList(int page, int size, QueryPageRequest queryPageRequest) {
  // 如果穿的对象为空
  if(queryPageRequest==null){
    queryPageRequest = new QueryPageRequest();
  }

  // 自定义条件查询
  // 条件匹配器
  ExampleMatcher exampleMatcher = ExampleMatcher.matching()
    .withMatcher("pageAliase",ExampleMatcher.GenericPropertyMatchers.contains());
  // 条件值对象
  CmsPage cmsPage = new CmsPage();
  // 设置条件值
  // 站点id
  if(StringUtils.isNotEmpty(queryPageRequest.getSiteId())){
    cmsPage.setSiteId(queryPageRequest.getSiteId());
  }
  // 设置模板id
  if(StringUtils.isNotEmpty(queryPageRequest.getTemplateId())){
    cmsPage.setTemplateId(queryPageRequest.getTemplateId());
  }
  // 设置页面别名
  if(StringUtils.isNotEmpty(queryPageRequest.getPageAliase())){
    cmsPage.setPageAliase(queryPageRequest.getPageAliase());
  }

  // 定义条件对象
  Example<CmsPage> example = Example.of(cmsPage,exampleMatcher);

  // 分页参数
  if(page<=0){
    page=1;
  }
  if(size<=0){
    size=10;
  }
  page = page-1;
  Pageable pageable = PageRequest.of(page,size);
  Page<CmsPage> all = cmsPageRepository.findAll(example,pageable);

  QueryResult queryResult = new QueryResult();
  queryResult.setTotal(all.getTotalElements());//数据总记录数
  queryResult.setList(all.getContent());//数据列表
  QueryResponseResult queryResponseResult = new QueryResponseResult(CommonCode.SUCCESS,queryResult);
  return queryResponseResult;
}
3. controller无需修改
4. 测试

用debug模式,使用SwaggerUI测试

3. 前端

1. 页面

增加查询表单

数据模型对象,增加siteList, pageAliase, siteId

在钩子方法中 构建siteList站点列表

<template>
<!--编写页面静态部分,即view部分-->
<div>
  <!--查询表单-->
  <el-form :model="params">
    <el-select v-model="params.siteId" placeholder="请选择站点">
      <el-option
                 v-for="item in siteList"
                 :key="item.siteId"
                 :label="item.siteName"
                 :value="item.siteId">
  </el-option>
  </el-select>
    页面别名:
    <el-input v-model="params.pageAliase" style="width: 100px"></el-input>
    <el-button type="primary" v-on:click="query" size="small">查询</el-button>
  </el-form>
  <el-button type="primary" size="small" v-on:click="query">查询</el-button>
  <el-table
            :data="list"
            stripe
            style="width: 100%">
    <el-table-column type="index" width="60">
  </el-table-column>
    <el-table-column prop="pageName" label="页面名称" width="120">
  </el-table-column>
    <el-table-column prop="pageAliase" label="别名" width="120">
  </el-table-column>
    <el-table-column prop="pageType" label="页面类型" width="150">
  </el-table-column>
    <el-table-column prop="pageWebPath" label="访问路径" width="250">
  </el-table-column>
    <el-table-column prop="pagePhysicalPath" label="物理路径" width="250">
  </el-table-column>
    <el-table-column prop="pageCreateTime" label="创建时间" width="180">
  </el-table-column>
  </el-table>
  <el-pagination
                 layout="prev, pager, next"
                 :total="total"
                 :page-size="params.size"
                 :current-page="params.page"
                 @current-change="changePage"
                 style="float:right">
  </el-pagination>
  </div>
</template>
<script>
  // 编写页面静态部分,即model和VM部分
  import * as cmsApi from '../api/cms'

  export default {
    data() {
      return {
        siteList: [],//站点列表
        list: [],
        total: 0,
        params: {
          siteId: '',
          pageAliase: '',
          page: 2,//页码
          size: 10 // 每页显示个数
        }
      }
    },
    methods: {
      query: function () {
        // alert('查询');
        // 调用服务端的接口
        cmsApi.page_list(this.params.page, this.params.size,this.params).then((res) => {
          // 将res结果数据赋值给数据模型对象
          this.list = res.queryResult.list;
          this.total = res.queryResult.total;
        })
      },
      changePage: function (page) {
        // 调用query方法
        this.params.page = page;
        this.query();
      }
    },
    mounted() {
      //默认查询页面
      this.query();
      // 初始化站点列表
      this.siteList = [
        /* {
          siteId: '5a751fab6abb5044e0d19ea1',
          siteName: '门户主站'
        }.
        {
          siteId: '102'.
          siteName: '测试站'
        }*/

        {
          siteId:'5a751fab6abb5044e0d19ea1',
          siteName:'门户主站'
        },
        {
          siteId:'102',
          siteName:'测试站'
        }
      ]
    }
  }
</script>
<style>
  /*编写页面样式,不是必须*/
</style>
2. api调用

向服务端传递查询条件,修改cms.js

// 页面查询
export const page_list = (page,size,params) =>{
  // 将params对象数据拼装成key/value串
  let queryStr = querystring.stringify(params);
  // 请求服务端的页面查询接口
  return http.requestQuickGet(apiUrl+'/cms/page/list/'+page+'/'+size+'?'+queryStr)
}

页面调用api方法,在methods方法中,见页面部分代码

测试,成功,记得前后端程序都要开…

2. 新增页面

1. 新增页面接口定义

1. 定义响应模型

已经定义好了

@Data
public class CmsPageResult extends ResponseResult {
  CmsPage cmsPage;
  public CmsPageResult(ResultCode resultCode,CmsPage cmsPage) {
    super(resultCode);
    this.cmsPage = cmsPage;
  }
}
2. 定义添加api

在api中添加接口

// 新增页面
@ApiOperation("新增页面")
public CmsPageResult add(CmsPage cmsPage);

2. 新增页面服务端开发

1. 页面唯一索引

在cms_page集上创建页面名称、站点id、页面webpath为唯一索引

studio 3T,集合上右键,add index,选取要添加的field,选择unique,成功会多个索引

2. dao

添加根据页面名称、站点Id、页面webpath查询页面方法,此方法用于校验页面是否存在

// 根据页面名称、站点id、页面webpath查询
CmsPage findByPageNameAndSiteIdAndPageWebPath(String pageName,String siteId,String pageWebPath);

使用的是本身的save方法

3. service
// 新增页面
public CmsPageResult add(CmsPage cmsPage){
  // 校验页面名称、站点id、页面webpath的唯一性
  // 根据页面名称、站点id、页面webpath去cms_page集合,如果查到说明此页面已经存在,如果查询不到继续添加
  CmsPage cmsPage1 = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(), cmsPage.getSiteId(), cmsPage.getPageWebPath());
  if(cmsPage1==null){
    // 调用dao新增页面
    cmsPage.setPageId(null);// 添加页面主键由springdata自动生成
    cmsPageRepository.save(cmsPage);
    return new CmsPageResult(CommonCode.SUCCESS,cmsPage);
  }
  // 添加失败
  return new CmsPageResult(CommonCode.FAIL,null);
}
4. controller

post方法提交,参数需要写requestbody注解

@Override
@PostMapping("/add")
public CmsPageResult add(@RequestBody CmsPage cmsPage) {
  return pageService.add(cmsPage);
}
5. 接口测试

同之前方法,post有example,直接选中,稍微修改即可

3. 新增页面前端开发

1. 新增页面
1. 编写page_add.vue页面

使用Element-UI的form组件编写添加表单内容,效果如下:

dya0301

  1. 创建page_add.vue页面
  2. 配置路由

在cms模块的路由文件中配置“添加页面”的路由:

{path:'/cms/page/add',name:'新增页面',component: page_add,hidden:true}

注意:由于“添加页面”不需要显示为一个菜单,这里hidden设置为true隐藏菜单

测试

  1. 在页面列表添加“添加页面”的按钮

实际情况是用户进入页面查询列表,点击“新增页面”按钮进入新增页面窗口

</el-select>
页面别名:
<el-input v-model="params.pageAliase" style="width: 100px"></el-input>
<el-button type="primary" v-on:click="query" size="small">查询</el-button>
<router-link :to="{path:'/cms/page/add',query:{
                  page: this.params.page,
                  siteId: this.params.siteId
                  }}">
  <el-button type="primary" size="small">新增页面</el-button>
</router-link>

说明:router-link是vue提供的路由功能,用于在页面生成路由链接,最终在html渲染后就是<a标签

to:目标路由地址

  1. 完善页面内容:
<template>
<!--编写页面静态部分,即view部分-->
<div>
  <el-form :model="pageForm" label-width="80px" :rules="pageFormRules" ref="pageForm">
    <el-form-item label="所属站点" prop="siteId">
      <el-select v-model="pageForm.siteId" placeholder="请选择站点">
        <el-option
                   v-for="item in siteList"
                   :key="item.siteId"
                   :label="item.siteName"
                   :value="item.siteId">
  </el-option>
  </el-select>
  </el-form-item>
    <el-form-item label="选择模版" prop="templateId">
      <el-select v-model="pageForm.templateId" placeholder="请选择">
        <el-option
                   v-for="item in templateList"
                   :key="item.templateId"
                   :label="item.templateName"
                   :value="item.templateId">
  </el-option>
  </el-select>
  </el-form-item>
    <el-form-item label="页面名称" prop="pageName">
      <el-input v-model="pageForm.pageName" auto-complete="off"></el-input>
  </el-form-item>
    <el-form-item label="别名" prop="pageAliase">
      <el-input v-model="pageForm.pageAliase" auto-complete="off"></el-input>
  </el-form-item>
    <el-form-item label="访问路径" prop="pageWebPath">
      <el-input v-model="pageForm.pageWebPath" auto-complete="off"></el-input>
  </el-form-item>
    <el-form-item label="物理路径" prop="pagePhysicalPath">
      <el-input v-model="pageForm.pagePhysicalPath" auto-complete="off"></el-input>
  </el-form-item>
    <el-form-item label="类型">
      <el-radio-group v-model="pageForm.pageType">
        <el-radio class="radio" label="0">静态</el-radio>
        <el-radio class="radio" label="1">动态</el-radio>
  </el-radio-group>
  </el-form-item>
    <el-form-item label="创建时间">
      <el-date-picker type="datetime" placeholder="创建时间" v-model="pageForm.pageCreateTime">
  </el-date-picker>
  </el-form-item>
  </el-form>
  <div slot="footer" class="dialog-footer">
    <el-button type="primary" @click="addSubmit">提交</el-button>
    <el-button type="primary" @click="go_back">返回</el-button>
  </div>
  </div>
</template>
<script>
  // 编写页面静态部分,即model和VM部分
  import * as cmsApi from '../api/cms'

  export default {
    data() {
      return {
        siteList: [],
        templateList: [],
        pageForm:{
          siteId:'',
          templateId:'',
          pageName: '',
          pageAliase: '',
          pageWebPath: '',
          pageParameter:'',
          pagePhysicalPath:'',
          pageType:'',
          pageCreateTime: new Date()
        },
        pageFormRules: {
          siteId:[
            {required: true, message: '请选择站点', trigger: 'blur'}
          ],
          templateId:[
            {required: true, message: '请选择模版', trigger: 'blur'}
          ],
          pageName: [
            {required: true, message: '请输入页面名称', trigger: 'blur'}
          ],
          pageWebPath: [
            {required: true, message: '请输入访问路径', trigger: 'blur'}
          ],
          pagePhysicalPath: [
            {required: true, message: '请输入物理路径', trigger: 'blur'}
          ]
        }
      }
    },
    methods: {
      addSubmit: function () {
        this.$refs.pageForm.validate((valid) => {
          if (valid) {
            // 确认提示
            this.$confirm('您确认提交吗?', '提示', {
              confirmButtonText: '确定',
              cancelButtonText: '取消',
            }).then(() => {
              // 调用page_add方法请求服务端的新增页面接口
              cmsApi.page_add(this.pageForm).then(res=>{
                if(res.success){
                  /*this.$message({
                    message: '提交成功',
                    // 将表单清空

                  })*/
                  this.$message.success('提交成功');
                  //将表单清空
                  this.$refs['pageForm'].resetFields();
                }else{
                  this.$message.error('提交失败')
                }
              });
            })

          }
        })
      },
      // 返回
      go_back: function () {
        this.$router.push({
          path:'/cms/page/list',
          query:{
            // 取出路由中的参数
            page:this.$route.query.page,
            siteId:this.$route.query.siteId
          }
        })
      }
    },
    mounted() {
      //初始化站点列表
      this.siteList = [
        {
          siteId:'5a751fab6abb5044e0d19ea1',
          siteName:'门户主站'
        },
        {
          siteId:'102',
          siteName:'测试站'
        }
      ]
      //模板列表
      this.templateList = [
        {
          templateId:'5a962b52b00ffc514038faf7',
          templateName:'首页'
        },
        {
          templateId:'5a962bf8b00ffc514038fafa',
          templateName:'轮播图'
        }
      ]
    }
  }
</script>
<style>
  /*编写页面样式,不是必须*/
</style>

Form Attributes说明:

  • model 表单数据对象 ; rules 表单验证规则 ;

Form-Item Attributes说明:

  • prop 表单域 model 字段,在使用 validate、resetFields 方法的情况下,该属性是必填的
  • label 标签文本
  1. 数据对象 ,见之前代码
  2. 站点及模板数据(先使用静态数据)

在created钩子方法中定义,created是在html渲染之前执行,这里推荐使用created。

2. 添加返回

进入新增页面后只能通过菜单再次进入页面列表,可以在新增页面添加“返回”按钮,点击返回按钮返回到页面列表。

  1. 新增页面按钮带上参数 说明:query表示在路由url上带上参数
  2. 定义返回方法 在page_add.vue上定义返回按钮 在page_add.vue上定义返回方法

说明:this.$route.query 表示取出路由上的参数列表,有两个取路由参数的方法

  • 通过在路由上添加key/value串使用this.$route.query来取参数,例如:/router1?id=123 ,/router1?id=456可以通过this.$route.query.id获取参数id的值。
  • 通过将参数作为路由一部分进行传参数使用this.$route.params来获取,例如:定义的路由为/router1/:id ,请求/router1/123时可以通过this.$route.params.id来获取,此种情况用this.$route.query.id是拿不到的
  1. 查询列表支持回显

进入查询列表,从url中获取页码和站点id并赋值给数据模型对象,从而实现页面回显。

// 还未渲染的时候执行
created(){
// 取出路由中的参数,赋值给数据对象
this.params.page = Number.parseInt(this.$route.query.page || 1);
this.params.siteId = this.$route.query.siteId || ''
},

小技巧:使用 ||返回第一个有效值

3. 表单校验
  1. 配置校验规则 在数据模型中配置校验规则
  2. 点击提交按钮触发校验

在form表单上添加 ref属性(ref=“pageForm”)在校验时引用此表单对象

执行校验

2. api调用
  1. 在cms.js中定义page_add方法
// 新增页面
export const page_add = params =>{
  return http.requestPost(apiUrl+'/cms/page/add/',params)
}
  1. 添加事件,代码见之前
    • 确认提交窗口
    • 提示操作结果

3. 修改页面

修改页面用户操作流程:

  1. 用户进入修改页面,在页面上显示了修改页面的信息
  2. 用户修改页面的内容,点击“提交”,提示“修改成功”或“修改失败”

1. 修改页面接口定义

修改页面需要定义的API如下:

// 根据页面id查询页面信息
@ApiOperation("根据页面id查询页面信息")
public CmsPage findById(String id);

// 修改页面
@ApiOperation("修改页面")
public CmsPageResult edit(String id,CmsPage cmsPage);

说明:提交数据使用post、put都可以,只是根据http方法的规范,put方法是对服务器指定资源进行修改,所以这里使用put方法对页面修改进行修改。

2. 修改页面服务端开发

1. dao

使用Spring Data提供的findById方法完成根据主键查询

使用Spring Data提供的save方法完成数据保存

2. service
// 根据页面id查询页面
public CmsPage getById(String id){
  Optional<CmsPage> optional = cmsPageRepository.findById(id);
  if(optional.isPresent()){
    CmsPage cmsPage = optional.get();
    return cmsPage;
  }
  return null;
}

// 修改页面
public CmsPageResult update(String id,CmsPage cmsPage){
  // 根据id从数据库查询页面信息
  CmsPage one = this.getById(id);
  if(one!=null){
    // 准备更新数据
    // 设置要修改的数据
    // 更新页面别名
    one.setPageAliase(cmsPage.getPageAliase());
    // 更新所属站点
    one.setSiteId(cmsPage.getSiteId());
    // 更新模板id
    one.setTemplateId(cmsPage.getTemplateId());
    // 更新页面名称
    one.setPageName(cmsPage.getPageName());
    // 更新访问路径
    one.setPageWebPath(cmsPage.getPageWebPath());
    // 更新物理路径
    one.setPagePhysicalPath(cmsPage.getPagePhysicalPath());
    // 提交修改
    cmsPageRepository.save(one);
    return new CmsPageResult(CommonCode.SUCCESS,one);
  }
  // 修改失败
  return new CmsPageResult(CommonCode.FAIL,null);
}
3. Controller
@Override
@GetMapping("/get/{id}")
public CmsPage findById(@PathVariable("id") String id) {
  return pageService.getById(id);
}

@Override
@PutMapping("/edit/{id}")//使用普通方法,http中put表示更新
public CmsPageResult edit(@PathVariable("id") String id,@RequestBody CmsPage cmsPage) {
  return pageService.update(id,cmsPage);
}

3. 修改页面前端开发

1. 页面处理流程

如下:

  1. 进入页面,通过钩子方法请求服务端获取页面信息,并赋值给数据模型对象
  2. 页面信息通过数据绑定到表单显示
  3. 用户修改信息点击“提交”请求服务端修改页面信息接口
2. 修改页面
1. 编写page_edit页面

修改页面的布局提那家页面,可以直接复制添加页面,在添加基础上修改

编写页面内容:

  1. 编写page_edit.vue 页面布局同添加页面
  2. 配置路由 进入修改页面传入pageId
import page_edit from '@/module/cms/page/page_edit.vue';
{path:'/cms/page/edit/:pageId',name:'修改页面',component: page_edit,hidden:true}
  1. 在页面列表添加“编辑”链接

在page_list.vue上添加“操作”列

<el‐table‐column label="操作" width="80">
  <template slot‐scope="page">
    <el‐button
               size="small"type="text"
               @click="edit(page.row.pageId)">编辑
      </el‐button>
  </template>
  </el‐table‐column>

编写edit方法

edit: function (pageId) {
  // 打开修改页面
  this.$router.push({
    path:'/cms/page/edit/'+pageId
  })
}

测试

2. 页面内容显示

功能实现:进入修改页面立即显示要修改的页面信息

  1. 定义api方法
// 根据id查询页面
export const page_get = id =>{
  return http.requestQuickGet(apiUrl+'/cms/page/get/'+id)
}
  1. 定义数据对象

进入修改页面传入pageId参数,在数据模型中添加pageId

<template>
<div>
  <el-form   :model="pageForm" label-width="80px" :rules="pageFormRules" ref="pageForm" >
    <el-form-item label="所属站点" prop="siteId">
      <el-select v-model="pageForm.siteId" placeholder="请选择站点">
        <el-option
                   v-for="item in siteList"
                   :key="item.siteId"
                   :label="item.siteName"
                   :value="item.siteId">
  </el-option>
  </el-select>
  </el-form-item>
    <el-form-item label="选择模版" prop="templateId">
      <el-select v-model="pageForm.templateId" placeholder="请选择">
        <el-option
                   v-for="item in templateList"
                   :key="item.templateId"
                   :label="item.templateName"
                   :value="item.templateId">
  </el-option>
  </el-select>
  </el-form-item>
    <el-form-item label="页面名称" prop="pageName">
      <el-input v-model="pageForm.pageName" auto-complete="off" ></el-input>
  </el-form-item>

    <el-form-item label="别名" prop="pageAliase">
      <el-input v-model="pageForm.pageAliase" auto-complete="off" ></el-input>
  </el-form-item>
    <el-form-item label="访问路径" prop="pageWebPath">
      <el-input v-model="pageForm.pageWebPath" auto-complete="off" ></el-input>
  </el-form-item>

    <el-form-item label="物理路径" prop="pagePhysicalPath">
      <el-input v-model="pageForm.pagePhysicalPath" auto-complete="off" ></el-input>
  </el-form-item>
    <el-form-item label="数据Url" prop="dataUrl">
      <el-input v-model="pageForm.dataUrl" auto-complete="off" ></el-input>
  </el-form-item>
    <el-form-item label="类型">
      <el-radio-group v-model="pageForm.pageType">
        <el-radio class="radio" label="0">静态</el-radio>
        <el-radio class="radio" label="1">动态</el-radio>
  </el-radio-group>
  </el-form-item>
    <el-form-item label="创建时间">
      <el-date-picker type="datetime" placeholder="创建时间" v-model="pageForm.pageCreateTime"></el-date-picker>
  </el-form-item>

  </el-form>
  <div slot="footer" class="dialog-footer">
    <el-button @click="go_back">返回</el-button>
    <el-button type="primary" @click.native="editSubmit" :loading="addLoading">提交</el-button>
  </div>
  </div>
</template>
<script>
  import * as cmsApi from '../api/cms'
  export default{
    data(){
      return {
        //页面id
        pageId:'',
        //模版列表
        templateList:[],
        addLoading: false,//加载效果标记
        //新增界面数据
        pageForm: {
          siteId:'',
          templateId:'',
          pageName: '',
          pageAliase: '',
          pageWebPath: '',
          dataUrl:'',
          pageParameter:'',
          pagePhysicalPath:'',
          pageType:'',
          pageCreateTime: new Date()
        },
        pageFormRules: {
          siteId:[
            {required: true, message: '请选择站点', trigger: 'blur'}
          ],
          templateId:[
            {required: true, message: '请选择模版', trigger: 'blur'}
          ],
          pageName: [
            {required: true, message: '请输入页面名称', trigger: 'blur'}
          ],
          pageWebPath: [
            {required: true, message: '请输入访问路径', trigger: 'blur'}
          ],
          pagePhysicalPath: [
            {required: true, message: '请输入物理路径', trigger: 'blur'}
          ]
        },
        siteList:[]
      }
    },
    methods:{
      go_back(){
        this.$router.push({
          path: '/cms/page/list', query: {
            page: this.$route.query.page,
            siteId:this.$route.query.siteId
          }
        })
      },
      editSubmit(){
        this.$refs.pageForm.validate((valid) => {
          if (valid) {
            this.$confirm('确认提交吗?', '提示', {}).then(() => {
              this.addLoading = true;
              // 修改提交请求服务端的接口
              cmsApi.page_edit(this.pageId,this.pageForm).then((res) => {
                console.log(res);
                if(res.success){
                  this.addLoading = false;
                  this.$message({
                    message: '提交成功',
                    type: 'success'
                  });
                  //返回
                  this.go_back();

                }else{
                  this.addLoading = false;
                  this.$message.error('提交失败');
                }
              });
            });
          }
        });
      }

    },
    created: function () {
      this.pageId=this.$route.params.pageId;
      //根据主键查询页面信息
      cmsApi.page_get(this.pageId).then((res) => {
        console.log(res);
        if(res){
          this.pageForm = res;
        }
      });
    },
    mounted:function(){

      //初始化站点列表
      this.siteList = [
        {
          siteId:'5a751fab6abb5044e0d19ea1',
          siteName:'门户主站'
        },
        {
          siteId:'102',
          siteName:'测试站'
        }
      ]
      //模板列表
      this.templateList = [
        {
          templateId:'5a962b52b00ffc514038faf7',
          templateName:'首页'
        },
        {
          templateId:'5a962bf8b00ffc514038fafa',
          templateName:'轮播图'
        }
      ]
    }
  }
</script>
<style>

</style>
  1. 在created钩子方法中查询页面信息
  2. 预览回显效果
3. api调用
  1. 定义api方法
// 修改页面提交
export const page_edit = (id,params) =>{
  return http.requestPut(apiUrl+'/cms/page/edit/'+id,params)
}
  1. 提交按钮,对应事件内容,见之前代码
  2. 测试

4. 删除页面

用户操作流程:

  1. 用户进入用户列表,点击“删除”
  2. 执行删除操作,提示“删除成功”或“删除失败”

1. 删除页面接口定义

// 删除页面
@ApiOperation("删除页面")
public ResponseResult delete(String id);

2. 删除页面服务端开发

1. dao

使用spring data提供的deleteById方法完成删除

2. service
// 根据id删除页面
public ResponseResult delete(String id){
  // 先查询一下
  Optional<CmsPage> optional = cmsPageRepository.findById(id);
  if(optional.isPresent()){
    cmsPageRepository.deleteById(id);
    return new ResponseResult(CommonCode.SUCCESS);
  }
  return new ResponseResult(CommonCode.FAIL);
}
3. controller
@Override
@DeleteMapping("/del/{id}")
public ResponseResult delete(String id) {
  return pageService.delete(id);
}

3. 前端

1. api方法
// 删除页面
export  const page_del = id =>{
  return http.requestDelete(apiUrl+'/cms/page/del/'+id)
}
2. 编写页面
  1. 在page_list.vue页面添加删除按钮
<el-table-column label="操作" width="80">
  <template slot-scope="page">
    <el-button
               size="small" type="text"
               @click="edit(page.row.pageId)">编辑
    </el-button>
    <el-button
               size="small" type="text"
               @click="del(page.row.pageId)">删除
    </el-button>
  </template>
</el-table-column>
  1. 删除事件
del:function (pageId) {
  this.$confirm('您确认删除吗?', '提示', { }).then(() => {

    //调用服务端接口
    cmsApi.page_del(pageId).then(res=>{

      if(res.success){
        this.$message.success("删除成功")
        //刷新页面
        this.query()
      }else{
        this.$message.error("删除失败")
      }
    })
  })

}
},

5. 异常处理

1. 异常处理的问题分析

从添加页面的service方法中,看到问题:

  1. 上面的代码只要操作不成功,仅向用户返回“错误代码:1111,失败信息:操作失败”,无法区别具体的异常信息
  2. service方法在执行过程出现异常在哪捕获?在service的话每个都要加try/catch,在controller也都要价try/catch,代码冗余且不易维护

解决方案:

  1. 在service方法中的编码顺序是先校验判断,有问题抛出具体的异常信息,最后执行具体的业务操作,返回成功信息
  2. 在统一异常处理类中去捕获异常,无需controller捕获异常,向用户返回统一规范的响应信息

2. 异常处理流程

系统对异常的处理使用统一的异常处理流程:

  1. 自定义异常类型
  2. 自定义错误代码及错误信息
  3. 对于可预知的异常由程序员在代码中主动抛出,由springMVC统一捕获

可预知异常是程序员在代码中手动抛出本系统定义的特定异常类型,通常信息齐全,会指定错误代码及错误信息,获取异常信息方便

  1. 对于不可预知的异常(运行时异常)由springMVC统一捕获Exception类型的异常

不可预知异常通常是由于系统出现bug,或一些不可抗因素(电缆被挖断),异常类型RuntimeException

  1. 可预知的异常及不可预知的运行时异常最终采用统一的信息格式(错误代码+错误提示)表示, 最终会随请求响应给客户端

异常抛出和处理流程

dya0302

  1. 在controller、service和dao中程序员抛出自定义异常,springMVC抛出框架异常类型
  2. 统一由异常捕获类捕获异常,并进行处理
  3. 捕获到自定义异常直接取出错误代码和错误信息,响应给客户
  4. 捕获到非自定义异常类型首先从map中找该异常类型是否对应具体的错误代码,如果有取出错误代码和错误信息响应给客户,如果从map中找不到异常类型对应的错误代码统一代码99999响应给客户
  5. 将错误代码及错误信息以json格式响应给用户。

3. 可预知异常处理

1. 自定义异常类

在common工程定义异常类型

public class CustomException extends RuntimeException{

  // 错误代码
  ResultCode resultCode;

  public CustomException(ResultCode resultCode){
    this.resultCode = resultCode;
  }

  public ResultCode getResultCode(){
    return resultCode;
  }
}
2. 异常抛出类
public class ExceptionCast {

  public static void cast(ResultCode resultCode){
    throw new CustomException(resultCode);
  }
}
3. 异常捕获类

使用@ControllerAdvice@ExceptionHandler注解来捕获指定类型的异常

@ControllerAdvice// 控制器增强
public class ExceptionCatch {

  private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionCatch.class);

  // 定义map,配置异常类型所对应的错误代码
  private static ImmutableMap<Class<? extends Throwable>,ResultCode> EXCEPTIONS;
  // 定义map的builder对象,构建ImmutableMap
  protected static ImmutableMap.Builder<Class<? extends Throwable>,ResultCode> builder = ImmutableMap.builder();

  // 捕获CustomException此类异常
  @ExceptionHandler(CustomException.class)
  @ResponseBody
  public ResponseResult customException(CustomException customException){
    // 记录日志
    LOGGER.error("catch exception:{}",customException.getMessage());
    ResultCode resultCode = customException.getResultCode();
    return new ResponseResult(resultCode);
  }

  // 捕获Exception此类异常
  @ExceptionHandler(Exception.class)
  @ResponseBody
  public ResponseResult exception(Exception exception){
    // 记录日志
    LOGGER.error("catch exception:{}",exception.getMessage());
    if(EXCEPTIONS == null){
      EXCEPTIONS  = builder.build();//EXCEPTIONS构建成功
    }
    // 从EXCEPTIONS中找异常类型对应的错误代码,如果找到,将错误代码响应给用户,如果找不到给用户响应99999异常
    ResultCode resultCode = EXCEPTIONS.get(exception.getClass());
    if(resultCode != null){
      return new ResponseResult(resultCode);
    }else{
      // 返回99999
      return new ResponseResult(CommonCode.SERVER_ERROR);
    }

  }

  static {
    // 定义异常类型对应的错误代码
    builder.put(HttpMessageNotReadableException.class,CommonCode.INVALID_PARAM);
  }
}
4. 异常处理测试
1. 定义错误代码

每个业务操作的异常使用异常代码去标识,已经被提前定义好了。

@ToString
public enum CmsCode implements ResultCode {
  CMS_ADDPAGE_EXISTSNAME(false,24001,"页面名称已存在!"),
  CMS_GENERATEHTML_DATAURLISNULL(false,24002,"从页面信息中找不到获取数据的url!"),
  CMS_GENERATEHTML_DATAISNULL(false,24003,"根据页面的数据url获取不到数据!"),
  CMS_GENERATEHTML_TEMPLATEISNULL(false,24004,"页面模板为空!"),
  CMS_GENERATEHTML_HTMLISNULL(false,24005,"生成的静态html为空!"),
  CMS_GENERATEHTML_SAVEHTMLERROR(false,24005,"保存静态html出错!"),
  CMS_COURSE_PERVIEWISNULL(false,24007,"预览页面为空!");
  //操作代码
  boolean success;
  //操作代码
  int code;
  //提示信息
  String message;
  private CmsCode(boolean success, int code, String message){
    this.success = success;
    this.code = code;
    this.message = message;
  }

  @Override
  public boolean success() {
    return success;
  }

  @Override
  public int code() {
    return code;
  }

  @Override
  public String message() {
    return message;
  }
}
2. 异常处理测试
  1. 抛出异常

在controller、service、dao都可以抛出异常

修改PageService的add方法,添加抛出异常的代码

// 新增页面
public CmsPageResult add(CmsPage cmsPage){
  // 校验cmsPage是否为空
  if(cmsPage==null){
    // 抛出异常
  }
  // 校验页面名称、站点id、页面webpath的唯一性
  // 根据页面名称、站点id、页面webpath去cms_page集合,如果查到说明此页面已经存在,如果查询不到继续添加
  CmsPage cmsPage1 = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(), cmsPage.getSiteId(), cmsPage.getPageWebPath());
  if(cmsPage1 !=null){
    // 页面已经存在
    // 抛出异常,异常内容就是页面已经存在
    ExceptionCast.cast(CmsCode.CMS_ADDPAGE_EXISTSNAME);
  }
  if(cmsPage1==null){
    // 调用dao新增页面
    cmsPage.setPageId(null);
    cmsPageRepository.save(cmsPage);
    return new CmsPageResult(CommonCode.SUCCESS,cmsPage);
  }
  // 添加失败
  return new CmsPageResult(CommonCode.FAIL,null);
}
  1. 启动工程,扫描到异常捕获的类ExceptionCatch

在SpringBoot的启动类中添加

@ComponentScan(basePackages = {"com.xuecheng.framework"})//扫描common工程的类
  1. 前端展示异常信息

服务端响应信息如下

dya0303

页面提取异常处理

addSubmit(){
  this.$refs.pageForm.validate((valid) => {
    if (valid) {
      this.$confirm('确认提交吗?', '提示', {}).then(() => {
        cmsApi.page_add(this.pageForm).then((res) => {
          console.log(res);
          if(res.success){
            this.$message({
              message: '提交成功',
              type: 'success'
            });
            this.$refs['pageForm'].resetFields();
          }else if(res.message){
            this.$message.error(res.message);
          }else{
            this.$message.error('提交失败');
          }
        });
      });
    }
  });
}

4. 不可预知异常处理

1. 定义异常捕获方法
1. 异常抛出测试

使用postman测试添加页面,不输入cmsPost信息,提交,报错信息如下

org.springframework.http.converter.HttpMessageNotReadableException

上边的响应信息在客户端无法解析

在异常捕获类中添加对Exception异常的捕获

@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseResult exception(Exception exception){
  //记录日志
  LOGGER.error("catch exception:{}",exception.getMessage());
  return null;
}
2. 异常捕获方法

针对上边的问题解决方案是:

  1. 我们在map中配置HttpMessageNotReadableException和错误代码
  2. 在异常捕获类中对Exception异常进行捕获,并从map中获取异常类型对应的错误代码,如果存在错误代码返回此错误,否则统一返回99999错误。

具体开发实现如下:

  1. 在通用错误代码类ConmmonCode中配置非法参数异常
INVALID_PARAM(false,10003,"非法参数!"),
  1. 在异常捕获类中配置HttpMessageNotReadableException为非法参数异常

异常捕获代码见之前的代码

3. 异常处理测试

仍然模拟“问题”中的测试步骤,异常结果为“非法参数”

6. 实战

1. 查询条件完善

页面查询条件增加:页面名称、页面类型

页面名称对应CmsPage模型类中的pageName属性

页面类型对应CmsPage模型类中的pageType属性

查询要求:

页面名称:模糊查询

页面类型:精确匹配,页面类型包括:静态和动态,在数据库静态用“0”,动态用“1”

2. 页面属性增加DataUrl

在CmsPage.java模型类型中有一个dataUrl属性,此属性在页面静态化时需要填写。

本需求要求:

  1. 在新增页面增加dataUrl输入框,并支持添加
  2. 在修改页面增加dataUrl输入框,并支持修改
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值