1 新建了sys_dict表以及相应Dict类保存菜单menu的icon数据
2 新建了sys_role_menu表以及相应RoleMenu类保存前端Role页面传来的角色菜单ID的绑定关系
3 在MenuController里增加获取Dict里icon的方法 提供前端菜单页面显示
4 在RoleController增加Post接口,获取前台传来的角色菜单绑定关系存到数据库;同时编写Get接口请求最新的角色菜单关系,提供前台角色页面显示
数据库
新建sys_dict表,储存菜单menu的icon数据
CREATE TABLE `sys_dict` (
`name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '名称',
`value` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '内容',
`type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '类型'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
新建sys_role_menu表,保存前端Role页面菜单分配得到的角色ID与菜单ID的关系
CREATE TABLE `sys_role_menu` (
`role_id` int NOT NULL COMMENT '角色id',
`menu_id` int NOT NULL COMMENT '菜单id',
PRIMARY KEY (`role_id`,`menu_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色菜单关系表';
后台代码
整体结构
主要完成以下任务:
1 新建了Dict类保存菜单menu的icon数据
2 新建了RoleMenu类保存前端Role页面传来的角色菜单ID的绑定关系
3 在MenuController里增加获取Dict里icon的方法
4 在RoleController增加更新接口,将前台得到的角色与菜单的绑定关系传到后台,然后存到数据库的表里【采用先删后增的方式】
entity/Dict.java
新建Dict实体类以及DictMapper
package com.zj.demo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@TableName("sys_dict")
@Data
public class Dict {
private String name;
private String value;
private String type;
}
DictMapper.java
package com.zj.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zj.demo.entity.Dict;
public interface DictMapper extends BaseMapper<Dict> {
}
common/Constants
在常量里增加icon类型,避免出错
package com.zj.demo.common;
public interface Constants {
String CODE_200 = "200"; //成功
String CODE_401 = "401"; // 权限不足
String CODE_400 = "400"; // 参数错误
String CODE_500 = "500"; // 系统错误
String CODE_600 = "600"; // 其他业务异常
String DICT_TYPE_ICON= "icon";
}
MenuController.java
增加获取icon的方法
package com.zj.demo.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zj.demo.common.Constants;
import com.zj.demo.common.Result;
import com.zj.demo.entity.Dict;
import com.zj.demo.entity.Menu;
import com.zj.demo.mapper.DictMapper;
import com.zj.demo.service.IMenuService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 前端控制器
* </p>
*
* @author Joyce
* @since 2023-01-10
*/
@RestController
@RequestMapping("/menu")
public class MenuController {
@Resource
private IMenuService menuService;
@Resource
private DictMapper dictMapper;
// 新增或者更新
@PostMapping
public Result save(@RequestBody Menu menu) {
return Result.success(menuService.saveOrUpdate(menu));
}
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
return Result.success(menuService.removeById(id));
}
@PostMapping("/del/batch")
public Result deleteBatch(@RequestBody List<Integer> ids) {
return Result.success(menuService.removeByIds(ids));
}
@GetMapping
public Result findAll(@RequestParam(defaultValue ="") String name) {
QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
if (!"".equals(name)) {
queryWrapper.like("name", name);
}
//查询所有数据
List<Menu> list = menuService.list(queryWrapper);
//找出pid为null的一级菜单
List<Menu> parentNode = list.stream().filter(menu -> menu.getPid() == null).collect(Collectors.toList());
//找出一级菜单的子菜单
for(Menu menu:parentNode){
//筛选所有数据中pid父级id的数据 作为二级菜单
menu.setChildren(list.stream().filter(m -> menu.getId().equals(m.getPid())).collect(Collectors.toList()));
}
return Result.success(parentNode);
}
@GetMapping("/{id}")
public Result findOne(@PathVariable Integer id) {
return Result.success(menuService.getById(id));
}
@GetMapping("/page")
public Result findPage(@RequestParam(defaultValue ="") String name,
@RequestParam Integer pageNum,
@RequestParam Integer pageSize) {
QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
if (!"".equals(name)) {
queryWrapper.like("name", name);
}
queryWrapper.orderByDesc("id");
return Result.success(menuService.page(new Page<>(pageNum, pageSize), queryWrapper));
}
@GetMapping("/icons")
public Result getIcons() {
QueryWrapper<Dict> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("type", Constants.DICT_TYPE_ICON);
return Result.success(dictMapper.selectList(queryWrapper));
}
}
entity/RoleMenu.java
新建角色菜单类
package com.zj.demo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@TableName("sys_role_menu")
@Data
public class RoleMenu {
private Integer roleId;
private Integer menuId;
}
RoleMenuMapper.java
package com.zj.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zj.demo.entity.RoleMenu;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface RoleMenuMapper extends BaseMapper<RoleMenu> {
@Delete("delete from sys_role_menu where role_id = #{roleId}")
int deleteByRoleId(@Param("roleId") Integer roleId);
@Select("select menu_id from sys_role_menu where role_id = #{roleId}")
List<Integer> selectByRoleId(Integer roleId);
}
RoleController.java
写一个更新接口,将前台得到的角色与菜单的绑定关系传到后台,然后存到数据库的表里【采用先删后增的方式】,具体功能在Service的setRoleMenu方法里完成【具体代码在RoleServiceImpl.java】
package com.zj.demo.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zj.demo.common.Result;
import com.zj.demo.entity.Role;
import com.zj.demo.service.IRoleService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* <p>
* 前端控制器
* </p>
*
* @author Joyce
* @since 2023-01-10
*/
@RestController
@RequestMapping("/role")
public class RoleController {
@Resource
private IRoleService roleService;
// 新增或者更新
@PostMapping
public Result save(@RequestBody Role role) {
return Result.success(roleService.saveOrUpdate(role));
}
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
return Result.success(roleService.removeById(id));
}
@PostMapping("/del/batch")
public Result deleteBatch(@RequestBody List<Integer> ids) {
return Result.success(roleService.removeByIds(ids));
}
@GetMapping
public Result findAll() {
return Result.success(roleService.list());
}
@GetMapping("/{id}")
public Result findOne(@PathVariable Integer id) {
return Result.success(roleService.getById(id));
}
@GetMapping("/page")
public Result findPage(
@RequestParam(defaultValue ="") String name,
@RequestParam Integer pageNum,
@RequestParam Integer pageSize) {
QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
if (!"".equals(name)) {
queryWrapper.like("name", name);
}
queryWrapper.orderByDesc("id");
return Result.success(roleService.page(new Page<>(pageNum, pageSize), queryWrapper));
}
/**
* 绑定角色与菜单的关系
* @param roleId 角色id
* @param menuIds 菜单id集合
* @return
*/
@PostMapping("roleMenu/{roleId}")
public Result roleMenu(@PathVariable Integer roleId,@RequestBody List<Integer> menuIds){
roleService.setRoleMenu(roleId,menuIds);
return Result.success();
}
/**
* 获取角色与菜单的关系
* @param roleId 角色id
* @param menuIds 菜单id集合
* @return
*/
@GetMapping("roleMenu/{roleId}")
public Result getroleMenu(@PathVariable Integer roleId){
return Result.success(roleService.getRoleMenu(roleId));
}
}
进入IRoleService
进入RoleServiceImpl
RoleServiceImpl.java
setRoleMenu方法编写, 有两种方法,
第一种使用QueryWrapper
第二种自己在Mapper里写delete方法【RoleMenuMapper.java——deleteByRoleId】
package com.zj.demo.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zj.demo.entity.Role;
import com.zj.demo.entity.RoleMenu;
import com.zj.demo.mapper.RoleMapper;
import com.zj.demo.mapper.RoleMenuMapper;
import com.zj.demo.service.IRoleService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
/**
* <p>
* 服务实现类
* </p>
*
* @author Joyce
* @since 2023-01-10
*/
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {
@Resource
private RoleMenuMapper roleMenuMapper;
@Transactional
@Override
public void setRoleMenu(Integer roleId, List<Integer> menuIds) {
//先删除当前角色id的所有绑定关系
// QueryWrapper<RoleMenu> queryWrapper = new QueryWrapper<>();
// queryWrapper.eq("role_id", roleId);
// roleMenuMapper.delete(queryWrapper);
roleMenuMapper.deleteByRoleId(roleId);
//再把前端传过来的菜单id和角色id进行绑定
// if (menuIds != null && menuIds.size() > 0)
// {
// menuIds.forEach(menuId -> {
// RoleMenu roleMenu = new RoleMenu();
// roleMenu.setMenuId(menuId);
// roleMenu.setRoleId(roleId);
// roleMenuMapper.insert(roleMenu);
// });
// }
for (Integer menuId : menuIds)
{
RoleMenu roleMenu = new RoleMenu();
roleMenu.setRoleId(roleId);
roleMenu.setMenuId(menuId);
roleMenuMapper.insert(roleMenu);
}
}
@Override
public List<Integer> getRoleMenu(Integer roleId) {
return roleMenuMapper.selectByRoleId(roleId);
}
}
前端代码
主要就是菜单页面的图标信息请求,以及角色页面菜单绑定数据的请求与上传
Menu.vue
请求icon数据,使得Menu前端的编辑里面的图标成为可选项
<template>
<div>
<div style="margin: 10px 0">
<el-input style="width: 200px" placeholder="请输入名称" suffix-icon="el-icon-search" v-model="name"></el-input>
<el-button class="ml-5" type="primary" @click="load">搜索</el-button>
<el-button type="warning" @click="reset">重置</el-button>
</div>
<div style="margin: 10px 0">
<el-button type="primary" @click="handleAdd1">新增 <i class="el-icon-circle-plus-outline"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定批量删除这些数据吗?"
@confirm="delBatch"
>
<el-button type="danger" slot="reference">批量删除 <i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
</div>
<el-table :data="tableData" border stripe :header-cell-class-name="'headerBg'"
row-key="id" default-expand-all @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="id" label="ID"></el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="path" label="路径"></el-table-column>
<el-table-column label="图标" class-name="fontSize16" align="center" label-class-name="fontSize12">
<template slot-scope="scope">
<span :class="scope.row.icon" />
</template>
</el-table-column>
<el-table-column prop="description" label="描述"></el-table-column>
<el-table-column label="操作" width="300" align="center">
<template slot-scope="scope">
<el-button type="primary" @click="handleAdd(scope.row.id)" v-if="!scope.row.pid && !scope.row.path">新增子菜单 <i class="el-icon-plus"></i></el-button>
<el-button type="success" @click="handleEdit(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定删除吗?"
@confirm="del(scope.row.id)"
>
<el-button type="danger" slot="reference">删除 <i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-dialog title="菜单信息" :visible.sync="dialogFormVisible" width="30%" >
<el-form label-width="80px" size="small">
<el-form-item label="名称">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="路径">
<el-input v-model="form.path" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="图标">
<el-select clearable v-model="form.icon" placeholder="请选择" style="width: 100%">
<el-option v-for="item in options" :key="item.name" :label="item.name" :value="item.value">
<i :class="item.value"/> {{ item.name }}
</el-option>
</el-select>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="form.description" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name: "Menu",
data() {
return {
tableData: [],
total: 0,
pageNum: 1,
pageSize: 10,
name: "",
path: "",
icon: "",
description: "",
form: {},
dialogFormVisible: false,
multipleSelection: [],
options:[]
}
},
created() {
this.load()
},
methods: {
load() {
this.request.get("/menu", {
params: {
name: this.name,
}
}).then(res => {
this.tableData = res.data
})
},
save() {
this.request.post("/menu", this.form).then(res => {
if (res.code === '200') {
this.$message.success("保存成功")
this.dialogFormVisible = false
this.load()
} else {
this.$message.error("保存失败")
}
})
},
del(id) {
this.request.delete("/menu/" + id).then(res => {
if (res.code === '200') {
this.$message.success("删除成功")
this.load()
} else {
this.$message.error("删除失败")
}
})
},
delBatch() {
let ids = this.multipleSelection.map(v => v.id) // [{}, {}, {}] => [1,2,3]
this.request.post("/menu/del/batch", ids).then(res => {
if (res.code === '200') {
this.$message.success("批量删除成功")
this.load()
} else {
this.$message.error("批量删除失败")
}
})
},
handleAdd1() {
this.dialogFormVisible = true
this.form = {}
},
handleAdd(pid) {
this.dialogFormVisible = true
this.form = {}
if(pid)
{
this.form.pid = pid
}
},
handleEdit(row) {
this.form = row
this.dialogFormVisible = true
// 请求图标的数据
this.request.get("/menu/icons").then(res => {
this.options = res.data
})
},
handleSelectionChange(val) {
console.log(val)
this.multipleSelection = val
},
reset() {
this.name = ""
this.load()
},
handleSizeChange(pageSize) {
console.log(pageSize)
this.pageSize = pageSize
this.load()
},
handleCurrentChange(pageNum) {
console.log(pageNum)
this.pageNum = pageNum
this.load()
},
}
}
</script>
<style>
.headerBg {
background: #eee!important;
}
.fontSize16{
font-size: 16px;
}
.fontSize12{
font-size: 12px;
}
</style>
Role.vue
1、菜单分配加个图标并弄成展开形式
2、编写菜单分配的确定按钮所绑定的saveRoleMenu()方法,
3、selectMenu()方法除了原有的请求菜单数据,还要请求已有的角色菜单数据
<template>
<div>
<div style="margin: 10px 0">
<el-input style="width: 200px" placeholder="请输入名称" suffix-icon="el-icon-search" v-model="name"></el-input>
<el-button class="ml-5" type="primary" @click="load">搜索</el-button>
<el-button type="warning" @click="reset">重置</el-button>
</div>
<div style="margin: 10px 0">
<el-button type="primary" @click="handleAdd">新增 <i class="el-icon-circle-plus-outline"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定批量删除这些数据吗?"
@confirm="delBatch"
>
<el-button type="danger" slot="reference">批量删除 <i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
<!-- <el-upload action="http://localhost:9090/role/import" :show-file-list="false" accept="xlsx" :on-success="handleExcelImportSuccess" style="display: inline-block">-->
<!-- <el-button type="primary" class="ml-5">导入 <i class="el-icon-bottom"></i></el-button>-->
<!-- </el-upload>-->
<!-- <el-button type="primary" @click="exp" class="ml-5">导出 <i class="el-icon-top"></i></el-button>-->
</div>
<el-table :data="tableData" border stripe :header-cell-class-name="'headerBg'" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="id" label="ID"></el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="description" label="描述"></el-table-column>
<el-table-column label="操作" width="280" align="center">
<template slot-scope="scope">
<el-button type="info" @click="selectMenu(scope.row.id)">分配菜单<i class="el-icon-menu"></i></el-button>
<el-button type="success" @click="handleEdit(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定删除吗?"
@confirm="del(scope.row.id)"
>
<el-button type="danger" slot="reference">删除 <i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<div style="padding: 10px 0">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[2, 5, 10, 20]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
<el-dialog title="角色信息" :visible.sync="dialogFormVisible" width="30%" >
<el-form label-width="80px" size="small">
<el-form-item label="名称">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="form.description" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
<el-dialog title="菜单分配" :visible.sync="menuDialogVis" width="30%">
<el-tree
:props="props"
:data="menuData"
show-checkbox
node-key="id"
ref="tree"
:default-expanded-keys="expends"
:default-checked-keys="checks">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span><i :class="data.icon"></i> {{ data.name }}</span>
</span>
</el-tree>
<div slot="footer" class="dialog-footer">
<el-button @click="menuDialogVis = false">取 消</el-button>
<el-button type="primary" @click="saveRoleMenu">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name: "Role",
data() {
return {
tableData: [],
total: 0,
pageNum: 1,
pageSize: 10,
name: "",
description: "",
form: {},
dialogFormVisible: false,
menuDialogVis: false,
multipleSelection: [],
menuData: [],
props:{
label:'name',
},
expends: [],
checks: [],
roleId: 0,
roleFlag: '',
ids: []
}
},
created() {
this.load()
},
methods: {
load() {
this.request.get("/role/page", {
params: {
pageNum: this.pageNum,
pageSize: this.pageSize,
name: this.name,
}
}).then(res => {
console.log(res)
this.tableData = res.data.records
this.total = res.data.total
})
},
save() {
this.request.post("/role", this.form).then(res => {
if (res.code === '200') {
this.$message.success("保存成功")
this.dialogFormVisible = false
this.load()
} else {
this.$message.error("保存失败")
}
})
},
del(id) {
this.request.delete("/role/" + id).then(res => {
if (res.code === '200') {
this.$message.success("删除成功")
this.load()
} else {
this.$message.error("删除失败")
}
})
},
delBatch() {
let ids = this.multipleSelection.map(v => v.id) // [{}, {}, {}] => [1,2,3]
this.request.post("/role/del/batch", ids).then(res => {
if (res.code === '200') {
this.$message.success("批量删除成功")
this.load()
} else {
this.$message.error("批量删除失败")
}
})
},
handleAdd() {
this.dialogFormVisible = true
this.form = {}
},
handleEdit(row) {
this.form = row
this.dialogFormVisible = true
},
handleSelectionChange(val) {
console.log(val)
this.multipleSelection = val
},
reset() {
this.name = ""
this.load()
},
handleSizeChange(pageSize) {
console.log(pageSize)
this.pageSize = pageSize
this.load()
},
handleCurrentChange(pageNum) {
console.log(pageNum)
this.pageNum = pageNum
this.load()
},
saveRoleMenu() {
this.request.post("/role/roleMenu/" + this.roleId, this.$refs.tree.getCheckedKeys()).then(res => {
if (res.code === '200') {
this.$message.success("绑定成功")
this.menuDialogVis = false
} else {
this.$message.error(res.msg)
}
})
},
selectMenu(roleId) {
this.menuDialogVis = true
this.roleId = roleId
//请求菜单数据
this.request.get("/menu").then(res =>
{
this.menuData = res.data
// 把后台返回的菜单数据处理成 id数组
this.expends = this.menuData.map(v => v.id)
})
//请求角色菜单数据
this.request.get("/role/roleMenu/" + this.roleId).then(res => {
this.checks = res.data
})
},
}
}
</script>
<style>
.headerBg {
background: #eee!important;
}
</style>
前端页面展示
菜单编辑图标显示
用户页面菜单分配设置为展开形式的图标
角色与菜单关系绑定,并且传输数据到后台,存入数据库
数据库里存入相应关系数据
Role页面加入角色菜单关系请求后,显示数据库内的关系数据
以4用户为例,分配菜单勾选主页、用户和文件后,点击确定,绑定成功
再次点开分配菜单,显示已有的菜单绑定数据
其他补充
@Resource和@Autowire的区别
@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字。
二者具体区别:
1、@Autowired与@Resource都可以用来装配bean.都可以写在字段上,或写在setter方法上。
2、@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false),如果我们想使用名称装配可以结合@Qualifier注解进行使用。
3、@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
IntelliJ Idea 常用快捷键列表
快捷键一览
Alt+Enter 导入包,自动修正【我们这里新建被调用方法用的就是这个】
Ctrl+N 查找类
Ctrl+Shift+N 查找文件
Ctrl+Alt+L 格式化代码
Ctrl+Alt+O 优化导入的类和包
Alt+Insert 生成代码(如get,set方法,构造函数等)
Ctrl+E或者Alt+Shift+C 最近更改的代码
Ctrl+R 替换文本
Ctrl+F 查找文本
Ctrl+Shift+Space 自动补全代码
Ctrl+空格 代码提示
Ctrl+Alt+Space 类名或接口名提示
Ctrl+P 方法参数提示
Ctrl+Shift+Alt+N 查找类中的方法或变量
Alt+Shift+C 对比最近修改的代码
Shift+F6 重构-重命名
Ctrl+Shift+先上键
Ctrl+B可以查看类或方法定义,但是不如ctrl+鼠标左键方便。
Ctrl+X 删除行
Ctrl+D 复制行
Ctrl+/ 或 Ctrl+Shift+/ 注释(// 或者/…/ )
Ctrl+J 自动代码
Ctrl+E 最近打开的文件
Ctrl+H 显示类结构图
Ctrl+Q 显示注释文档
Alt+F1 查找代码所在位置
Alt+1 快速打开或隐藏工程面板
Ctrl+Alt+ left/right 返回至上次浏览的位置
Alt+ left/right 切换代码视图
Alt+ Up/Down 在方法间快速移动定位
Ctrl+Shift+Up/Down 代码向上/下移动。
F2 或Shift+F2 高亮错误或警告快速定位
代码标签输入完成后,按Tab,生成代码。
选中文本,按Ctrl+Shift+F7 ,高亮显示所有该文本,按Esc高亮消失。
Ctrl+W 选中代码,连续按会有其他效果
选中文本,按Alt+F3 ,逐个往下查找相同文本,并高亮显示。
Ctrl+Up/Down 光标跳转到第一行或最后一行下
Ctrl+B 快速打开光标处的类或方法
最常用快捷键
1.Ctrl+E,可以显示最近编辑的文件列表
2.Shift+Click可以关闭文件
3.Ctrl+[或]可以跳到大括号的开头结尾
4.Ctrl+Shift+Backspace可以跳转到上次编辑的地方
5.Ctrl+F12,可以显示当前文件的结构
6.Ctrl+F7可以查询当前元素在当前文件中的引用,然后按F3可以选择
7.Ctrl+N,可以快速打开类
8.Ctrl+Shift+N,可以快速打开文件
9.Alt+Q可以看到当前方法的声明
10.Ctrl+W可以选择单词继而语句继而行继而函数
11.Alt+F1可以将正在编辑的元素在各个面板中定位
12.Ctrl+P,可以显示参数信息
13.Ctrl+Shift+Insert可以选择剪贴板内容并插入
14.Alt+Insert可以生成构造器/Getter/Setter等
15.Ctrl+Alt+V 可以引入变量。例如把括号内的SQL赋成一个变量
16.Ctrl+Alt+T可以把代码包在一块内,例如try/catch
17.Alt+Up and Alt+Down可在方法间快速移动
下面的不是很有用
18.在一些地方按Alt+Enter可以得到一些Intention Action,例如将”==”改为”equals()”
19.Ctrl+Shift+Alt+N可以快速打开符号
20.Ctrl+Shift+Space在很多时候都能够给出Smart提示
21.Alt+F3可以快速寻找
22.Ctrl+/和Ctrl+Shift+/可以注释代码
23.Ctrl+Alt+B可以跳转到抽象方法的实现
24.Ctrl+O可以选择父类的方法进行重写
25.Ctrl+Q可以看JavaDoc
26.Ctrl+Alt+Space是类名自动完成
27.快速打开类/文件/符号时,可以使用通配符,也可以使用缩写
28.Live Templates! Ctrl+J
29.Ctrl+Shift+F7可以高亮当前元素在当前文件中的使用
30.Ctrl+Alt+Up /Ctrl+Alt+Down可以快速跳转搜索结果
31.Ctrl+Shift+J可以整合两行
32.Alt+F8是计算变量值