情景描述:Ruoyi框架自动生成的代码,对应的只按照一个主键来进行操作,在面临多个或联合主键时,会出现操作上的误解。

推荐解决方法:调整后端接口逻辑。

问题阐述:

1、打开管理员后台,在页面内进行新增操作。(假设对应的联合主键表为:A)

发现只是将对应的修改。

2、直接在数据库中添加2条数据。选择修改,报错。

3、删除时,会直接将同id下的数据全部删除

问题定位

1、查看前端页面:(此处以一般生成的代码为例)

(1)定位到对应的.vue文件,一般在ruoyi-ui模块的src目录,views下

比如我的:ruoyi-ui/src/views/user_fill_content/user_content/index.vue

(2)找到对应的修改和增加代码区域:定位到JS逻辑处理区

(3)定位到submitForm()函数,发现是form的值来进行操作的,而form的获取由按钮处理操作来获取。

(4)我们发现,按钮处理操作是按照一个单独的id来判断,并非是双主键,问题所在。

(5)删除同理:

2、定位后端接口:

(1)找到<script>开头的import,crtl+左键,点进去。找url,选中末尾,crtl+左键

(2)下面以删除为例:查看对应的mapper.xml

(3)定位到删除:发现如猜测一样,单主键进行操作。比如我的:

<delete id="deleteUserFillContentBySpecificEventId" parameterType="Long">
   delete from user_fill_content where specific_event_id = #{specificEventId}
</delete>
<!--我的表中,还有个user_id,联合做主键-->

解决步骤

1、在Mapper.xml文件中:

(这是各层示意图)

重写sql(建议重命名,以便区分):完成查找和删除的操作。

<!--查找:id可以随便起,需要和mapper.java类中方法一致,-->
<!--这里我parameterType用的Map,方便接口传递多个主键,且更直观。-->
<!--在where 语句里把主键属性补上即可,比如我这两个属性:specificEventId与userId-->
<select id="selectUserFillContentBySpecificEventIdAndUserId" parameterType="java.util.Map"     
      resultMap="UserFillContentResult">
        <include refid="selectUserFillContentVo"/>
        where specific_event_id = #{specificEventId} and user_id = #{userId}
</select>

<delete id="deleteUserFillContentBySpecificEventIdAndUserId" parameterType="java.util.Map"         
    delete from user_fill_content 
    where specific_event_id = #{specificEventId} and user_id = #{userId}
</delete>

限制修改操作的属性,注意此处。业务规则:主键部分不让修改

    <update id="updateUserFillContent" parameterType="com.ruoyi.act.user_fill_content.domain.UserFillContent">
        update user_fill_content
        <trim prefix="SET" suffixOverrides=",">
            <if test="specificFillContent != null and specificFillContent != ''">specific_fill_content = #{specificFillContent},</if>
<!--  注释掉这个主键   <if test="userId != null">user_id = #{userId},</if>-->
            <if test="formId != null">form_id = #{formId},</if>
        </trim>
        where specific_event_id = #{specificEventId} and user_id=#{userId}
<!-- 依据联合主键来定位-->
    </update>

2、修改mapper.java文件:

public int deleteUserFillContentBySpecificEventIdAndUserId(Map usermap);
//把方法名称换为你在xml写的id
public UserFillContent selectUserFillContentBySpecificEventIdAndUserId(Map userMap);

3、返回service层,在接口中新增方法:

        比如我的:IUserFillContentService

直接把上文添加的复制过来就可以。名称可以自定义,但建议保持和上文一致,注释可以不写。

    /**
     * 依据具体事件编号和用户id查询用户填写内容
     *
     * @param specificEventId 用户填写内容主键
     *         userId         填写者编号
     * @return 用户填写内容
     */
public UserFillContent selectUserFillContentBySpecificEventIdAndUserId(Map userMap);

    /**
     * 依据具体事件编号和用户id删除用户填写内容
     *
     * @param usermap 用户填写内容主键
     * @return 结果
     */
public int deleteUserFillContentBySpecificEventIdAndUserId(Map usermap);

4、在impl中实现方法

比如我的:UserFillContentServiceImpl文件

//方法的返回值,就是对应的Mapper文件中,我们新增的方法的返回值。直接xxMapper.就行
//注意;方法返回值要保持一致。方法参数一直是Map

@Override
    public int deleteUserFillContentBySpecificEventIdAndUserId(Map usermap) {
        return userFillContentMapper.deleteUserFillContentBySpecificEventIdAndUserId(usermap);
    }
}

    @Override
    public UserFillContent selectUserFillContentBySpecificEventIdAndUserId(Map userMap) {
        return userFillContentMapper.selectUserFillContentBySpecificEventIdAndUserId(userMap);
    }

5、返回Controller层,添加接口

比如我的:UserFillContentController文件

    @ApiOperation("依据具体事件编号和用户id删除用户填写内容")
    //这是权限验证,可以注释掉不管@PreAuthorize("@ss.hasPermi('user_fill_content:user_content:remove')")
    @Log(title = "用户填写内容", businessType = BusinessType.DELETE)
    //日志相关
    @DeleteMapping("/{specificEventId}/{userId}")
    //写你的接口使用形式,这里直接对应的传递所有主键即可,比如我的specificEventId、userId
    //removeBySpeId_UserId为自定义名称
    public AjaxResult removeBySpeId_UserId(@PathVariable Long specificEventId,@PathVariable Long userId)
//@PathVariable说明需要的参数,一共两个
    {
        HashMap<String, Object> userMap = new HashMap<>();
        userMap.put("specificEventId",specificEventId);
        userMap.put("userId",userId);
//以map的形式存储,从而接收所有主键。
        return toAjax(userFillContentService.deleteUserFillContentBySpecificEventIdAndUserId(userMap));
    }


    @ApiOperation("依据具体事件编号和用户id获取用户填写内容详细信息")
    //@PreAuthorize("@ss.hasPermi('user_fill_content:user_content:query')")
    @GetMapping(value = "/{specificEventId}/{userId}")
    public AjaxResult getInfoBySpeId_UserId(@PathVariable("specificEventId") Long specificEventId,@PathVariable("userId") Long userId)
    {
        HashMap<String, Object> userMap = new HashMap<>();
        userMap.put("specificEventId",specificEventId);
        userMap.put("userId",userId);
        return success(userFillContentService.selectUserFillContentBySpecificEventIdAndUserId(userMap));
    }

6、在前端的src/api文件夹中,新增我们添加的接口

比如我的:user_content.js文件

//依据具体事件编号和用户id获取用户填写内容详细信息
export function getInfoBySpeId_UserId(specificEventId,userId) {
  return request({
    url: '/user_fill_content/user_content/' + specificEventId + '/' +userId,
    method: 'get'
  })
}
//这一步就是把上一步写的复制下

//把名字和参数替换为你的即可

// 依据具体事件编号和用户id删除用户填写内容
export function removeBySpeId_UserId(specificEventId,userId) {
  return request({
    url: '/user_fill_content/user_content/' + specificEventId+ '/' +userId,
    method: 'delete'
  })
}

7、返回前端vue文件中,修改相关逻辑

(1)引入新添加的接口,import导入:

import {removeBySpeId_UserId,  getInfoBySpeId_UserId} from  "@/api/user_fill_content/user_content";

(2)修改按钮操作的处理逻辑:

在data内定义一个数组,存储选择的id

//在data内定义一个数组,用于选中时定位id
data() {
    return {
        userIds: [], //定义的id
    }
}

找到:handleSelectionChange()方法:进行userIds的数据获取

// 多选框选中数据
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.specificEventId)
      this.userIds = selection.map(item => item.userId) //新增方法,和上一行类似
      this.single = selection.length !== 1
      this.multiple = !selection.length
    },

声明一个对象,用于存储另一个主键。同时更改接口的使用。

    /** 修改按钮操作 */
    handleUpdate(row) {
      this.reset();
      const specificEventId = row.specificEventId || this.ids
      const userId = row.userId || this.userIds //这是新添加的
      //将接口换为你写的get,比如我的为:getInfoBySpeId_UserId,获取准确的内容
      getInfoBySpeId_UserId(specificEventId, userId).then(res => {
        this.form = res.data;
        this.open = true;
        this.title = "修改用户填写内容";
      });

(3)修改删除逻辑:

   /** 删除按钮操作 */
    handleDelete(row) {
      const specificEventId = row.specificEventId || this.ids;
      const userId = row.userId || this.userIds;//这是新添加的
      this.$modal.confirm('是否确认删除用户填写内容编号为"' + specificEventId +'用户编号为:'+ userId +  '"的数据项?').then(function () {
         //将接口换为你写的delete,比如我的为:removeBySpeId_UserId,定位准确的内容
        return removeBySpeId_UserId(specificEventId,userId);
      }).then(() => {
        this.getList();
        this.$modal.msgSuccess("删除成功");
      }).catch(() => {
      });
    },

(4)建议分开添加或修改用户填写内容对话框:

v-if="title==='修改用户填写内容'"
//在<el-dialog>标签内,替换为你的对应的操作title

对应的@click也更改下,一个添加、一个修改。

(5)完善添加、修改逻辑


    /** 添加按钮 */

    submitForm_add() {
      this.$refs["form"].validate(valid => {
        if (valid) {
          addUser_content(this.form).then(response => {
            this.$modal.msgSuccess("新增成功");
            this.open = false;
            this.getList();
          });
        }
      });
    },
    /** 修改按钮 */
    submitForm_update() {
      this.$refs["form"].validate(valid => {
            if (valid)) {
              updateUser_content(this.form).then(response => {
                this.$modal.msgSuccess("修改成功");
                this.open = false;
                this.getList();
              });
            }
          });
    },

8、保存后,刷新前后端,重新运行。

验证:

1、新增:

(1)添加前:

(2)添加后:

2、修改:

(1)选择修改

(2)修改之后

3、删除:

(1)选择删除

(2)删除后

验证完毕,整体符合正常使用的逻辑。因为整体书写花费时间比较长,可能有些地方存在遗漏,欢迎补充。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐