易用宝项目记录day6-login和权限管理

1.登录界面

位置:webapp/WEB-INF/views/login.jsp

主要的是js使用easyui的ajax发送post请求

<%--User: xjDate: 2019/7/10Time: 16:26
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html lang="zh-cn">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/><meta name="renderer" content="webkit"><title>登录</title><%@ include file="/WEB-INF/views/head.jsp" %><link rel="stylesheet" href="/css/base.css"><link rel="stylesheet" href="/css/style.css"><script type="text/javascript">//判断当前页面是否是顶层页面if (top != window) {//window.top.location.href = "/login";window.top.location.href = window.location.href;}//回车登录$(document.documentElement).on("keyup", function (event) {console.debug(event);var keyCode = event.keyCode;if (keyCode === 13) { // 捕获回车submitForm(); // 提交表单}});//提交form表单function submitForm() {$('#loginForm').form('submit', {url: "/login",onSubmit: function () {return $(this).form('validate');},//注意:现在这个data是一个字符串:{success:true,msg:""}success: function (data) {var result = JSON.parse(data);if (result.success) {//如果登录成功,跳转到主页面window.location.href = "/main";} else {//如果登录失败,给出错误提示$("#msg").text(result.msg);setTimeout(function () {$("#msg").hide().text("");}, 2000);$("#msg").show();//$.messager.alert('错误', result.msg);}}});}</script></head>
<body><div class="bg"></div>
<div class="container"><div class="line bouncein"><div class="xs6 xm4 xs3-move xm4-move"><div style="height:150px;"></div><div class="media media-y margin-big-bottom"></div><form id="loginForm" action="/login" method="post" class="easyui-form"><div class="panel loginbox"><div class="text-center margin-big padding-big-top"><h1>欢迎来到易用宝</h1></div><div class="panel-body" style="padding:30px; padding-bottom:10px; padding-top:10px;"><div class="form-group"><div class="field field-icon-right"><input type="text" class="input input-big" name="username" id="username"placeholder="登录账号"/><span class="icon icon-user margin-small"></span></div></div><div class="form-group"><div class="field field-icon-right"><input type="password" class="input input-big" name="password" id="password"placeholder="登录密码"/><span class="icon icon-key margin-small"></span></div></div><div class="form-group"><div class="field"><input type="text" class="input input-big" name="captcha" placeholder="填写右侧的验证码"/><img src="/images/captcha"alt="" width="100" height="32" class="passcode" style="height:43px;cursor:pointer;"onClick="this.src=this.src+'?'"></div></div></div><div class="form-group"><div class="field field-icon-right"><h3 id="msg" style="text-align: center;color: red"></h3></div></div><div style="padding:30px;"><input type="button" id="button" class="button button-block bg-main text-big input-big"onclick="submitForm();" value="登录"></div></div></form></div></div>
</div></body>
</html>

2.LoginController功能

准备两个/login,一个get用于跳转页面,一个post用于登录

package cn.xiaji.web.controller;
//encoding: utf-8import cn.xiaji.common.JsonResult;
import com.wf.captcha.Captcha;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.utils.CaptchaUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import sun.security.util.Password;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.util.Random;/*** @author: xj* @contact: xiaruji520@gmail.com* @file: LoginController.java*/
/**/
@Controller
public class LoginController {private Font getFont() {Random random = new Random();Font font[] = new Font[6];font[0] = new Font("Ravie", Font.PLAIN, 32);font[1] = new Font("Antique Olive Compact", Font.PLAIN, 32);font[2] = new Font("Forte", Font.PLAIN, 32);font[3] = new Font("Wide Latin", Font.PLAIN, 32);font[4] = new Font("Gill Sans Ultra Bold", Font.PLAIN, 32);font[5] = new Font("Verdana", Font.PLAIN, 32);return font[random.nextInt(6)];}//验证码@RequestMapping("/images/captcha")public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {/*https://github.com/whvcse/EasyCaptcha*/// 设置请求头为输出图片类型CaptchaUtil.setHeader(response);// 三个参数分别为宽、高、位数SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);// 设置字体specCaptcha.setFont(getFont());// 设置类型,纯数字、纯字母、字母数字混合specCaptcha.setCharType(Captcha.TYPE_DEFAULT);// 验证码存入sessionrequest.getSession().setAttribute("captcha", specCaptcha.text().toLowerCase());// 生成的验证码String code = specCaptcha.text();System.out.println(code);// 输出图片流specCaptcha.out(response.getOutputStream());}/*@PostMapping("/login")public JsonResult login(String username, String password, String code){// 获取session中的验证码String sessionCode = request.getSession().getAttribute("captcha");// 判断验证码if (code==null || !sessionCode.equals(code.trim().toLowerCase())) {return JsonResult.error("验证码不正确");}}*/@RequestMapping(value = "/login", method = RequestMethod.GET)public String index() {return "login";}@RequestMapping(value = "/login", method = RequestMethod.POST)@ResponseBodypublic JsonResult login(HttpServletRequest request, String username, String password, String captcha) {// 获取session中的验证码String code = (String) request.getSession().getAttribute("captcha");//判断验证码是否正确if (code.equals(captcha.toLowerCase())) {System.out.println("验证码成功!" + username + "-----" + password);//1.拿到当前用户Subject subject = SecurityUtils.getSubject();//2.如果没有登录就让它登录if (!subject.isAuthenticated()) {UsernamePasswordToken token = new UsernamePasswordToken(username, password);try {subject.login(token);return new JsonResult();} catch (UnknownAccountException e) {System.out.println("用户名或者密码错误!");e.printStackTrace();return new JsonResult(false, "用户名或者密码错误!");} catch (IncorrectCredentialsException e) {System.out.println("用户名或者密码错误!");e.printStackTrace();return new JsonResult(false, "用户名或者密码错误!");} catch (AuthenticationException e) {System.out.println("未知错误!");e.printStackTrace();return new JsonResult(false, "未知错误!");}}return new JsonResult(false, "用户名或者密码错误!");} else {return new JsonResult(false, "验证码错误!");}}//登出:注销功能@RequestMapping("/logout")public String logout(){//拿到主体完成登出Subject subject = SecurityUtils.getSubject();subject.logout();//跳回到登录页面return "redirect:/login";}}

3.密码安全问题(MD5+循环加盐)

准备一个util

package cn.xiaji.common;
//encoding: utf-8import org.apache.shiro.crypto.hash.SimpleHash;/*** @author: xj* @contact: xiaruji520@gmail.com* @file: MD5Utils.java*/
/**/
public class MD5Utils {//加盐public static final String salt = "xxxx";//xxxx代表你的盐值//加密次数public static final int HASHITERATIONS = 1000;//加密循环次数public static String createMD5Pwd(String str) {SimpleHash hash = new SimpleHash("MD5", str, salt, HASHITERATIONS);return hash.toHex();}
}

在EmployeeServiceImpl 添加用户密码

package cn.xiaji.service.Impl;
//encoding: utf-8import cn.xiaji.common.MD5Utils;
import cn.xiaji.domain.Employee;
import cn.xiaji.repository.EmployeeRepository;
import cn.xiaji.service.IEmployeeService;
import com.hazelcast.util.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** @author: xj* @contact: xiaruji520@gmail.com* @file: EmployeeServiceImpl.java*/
/**/
@Service
public class EmployeeServiceImpl extends BaseServiceImpl<Employee, Long> implements IEmployeeService {@Autowiredprivate EmployeeRepository employeeRepository;//验证用户名是否存在@Overridepublic Boolean checkUsername(String username) {return !(employeeRepository.getCountByUsername(username) > 0);}@Overridepublic Employee findByUsername(String username) {return  employeeRepository.findByUsername(username);}//添加或更新 密码加密@Override@Transactionalpublic void save(Employee employee) {if (employee.getId() == null) {employee.setPassword(MD5Utils.createMD5Pwd(employee.getPassword()));}super.save(employee);}
}

applicationContext-shiro.xml也要注意(编码方式与次数)

 <!-- 等会需要改成自己的Realm --><bean id="jdbcRealm" class="cn.xiaji.web.shiro.AISellRealm"><!--密码的匹配器--><property name="credentialsMatcher"><bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"><property name="hashAlgorithmName" value="MD5"/><property name="hashIterations" value="1000"/></bean></property></bean>

FilterChainDefinitionMapFactory静态资源放行

package cn.xiaji.web.shiro;
//encoding: utf-8import java.util.LinkedHashMap;
import java.util.Map;/*** @author: xj* @contact: xiaruji520@gmail.com* @file: FilterChainDefinitionMapFactory.java*/
/**/
public class FilterChainDefinitionMapFactory {public Map<String, String> builderFilterChainDefinitionMap() {Map<String, String> maps = new LinkedHashMap<>();//maps中加数据//设置放行maps.put("/s/*", "anon");maps.put("/login", "anon");maps.put("/easyui/**", "anon");maps.put("/js/**", "anon");maps.put("/json/**", "anon");maps.put("/css/**", "anon");maps.put("*.js", "anon");maps.put("*.css", "anon");maps.put("/images/**", "anon");//设置权限拦截maps.put("/employee/index", "perms[employee:index]");maps.put("/dept/index", "perms[dept:index]");//设置拦截所有maps.put("/**", "authc");return maps;}
}

4.权限管理-角色管理

  1. 先在domain层建立好多对多关系

  2. role.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head><title>易用宝,Role管理</title><%@include file="/WEB-INF/views/head.jsp" %><script src="/js/model/role.js"></script>
    </head>
    <body><%--pagination:分页--%>
    <table id="roleGrid" class="easyui-datagrid"data-options="url:'/role/page',fitColumns:true,singleSelect:false,pagination:true,<%--onDblClickCell:onDblClickCell,--%>toolbar:'#gridTools',onRowContextMenu:showMenu"><thead><tr><th data-options="field:'id',width:100">id</th><th data-options="field:'name',width:100">名称</th><th data-options="field:'sn',width:100">编码</th><th data-options="field:'permissions',width:100,formatter:permsFormat">权限</th></tr></thead>
    </table><%--右键支持增删改--%>
    <div id="gridMenu" class="easyui-menu" style="width:120px;"><div data-options="iconCls:'icon-add'" data-method="add">添加</div><div data-options="iconCls:'icon-edit'" data-method="update">修改</div><div data-options="iconCls:'icon-remove'" data-method="del">删除</div><div data-options="iconCls:'icon-remove'" data-method="delMore">批量删除</div>
    </div><%--grid顶部工具栏--%>
    <div id="gridTools" style="padding:5px;height:auto"><%--功能条--%><div style="margin-bottom:5px"><a href="#" data-method="add" class="easyui-linkbutton" iconCls="icon-add" plain="true">添加</a><a href="#" data-method="update" class="easyui-linkbutton" iconCls="icon-edit" plain="true">修改</a><a href="#" data-method="del" class="easyui-linkbutton" iconCls="icon-remove" plain="true">删除</a><a href="#" data-method="delMore" class="easyui-linkbutton" iconCls="icon-remove" plain="true">批量删除</a></div><%--查询条--%><form id="searchForm">名称:<input name="name" class="easyui-textbox" style="width:80px"><a href="#" data-method="search" class="easyui-linkbutton" iconCls="icon-search">查询</a></form>
    </div><%--添加与修改的表单对话框--%>
    <div id="editDialog" class="easyui-dialog" title="功能编辑" style="width:950px;"data-options="iconCls:'icon-save',resizable:true,modal:true,closed:true"><form id="editForm" method="post"><input id="roleId" type="hidden" name="id"/><table cellpadding="5" style="width: 100%"><tr><td>名称:<input class="easyui-validatebox" type="text" name="name"data-options="required:true"/>&emsp; &emsp;编码:<input class="easyui-validatebox" type="text" name="sn"data-options="required:true"/></td></tr><tr><td><div id="cc" class="easyui-layout" style="width:99%;height:400px;"><div data-options="region:'west'" style="width:440px;"><table id="userPermissionGrid"></table></div><div data-options="region:'center'"><table id="allPermissionGrid"></table></div></div></td></tr></table></form><div style="text-align:center;padding:5px"><a href="javascript:void(0)" class="easyui-linkbutton" data-method="save">提交</a><a href="javascript:void(0)" class="easyui-linkbutton" data-method="closeDialog">关闭</a></div>
    </div></body>
    </html>
    
  3. role.js

    //右键支持增删改
    function showMenu(e, rowIndex, rowData) {//选中这个行$("#roleGrid").datagrid("selectRow", rowIndex);//第0个位置的面板不支持相应功能e.preventDefault();$('#gridMenu').menu('show', {left: e.pageX,top: e.pageY});
    }//对权限进行相应的格式化
    function permsFormat(val) {var permsStr = "";for (let o of val) {permsStr += o.name + " ";}return permsStr;
    }$(function () {//获取常用组件(分页/查询条)var roleGrid = $("#roleGrid");var searchForm = $("#searchForm");var editDialog = $("#editDialog");var editForm = $("#editForm");//绑定事件$("*[data-method]").on("click", function () {var method = $(this).data("method");//动态调用window.xiaji[method]();});xiaji = {//查询search() {//serializeObject:可以拿到form中的所有数据,封装成json对象var params = searchForm.serializeObject();roleGrid.datagrid("load", params);},//关闭窗口closeDialog() {editDialog.dialog("close");},//添加add() {//让密码框显示$("*[data-edit]").show();$("*[data-edit] input").validatebox("enable");//修改弹出框TitleeditDialog.dialog('setTitle', "添加");//清空form中的数据editForm.form("clear");//清空左边grid的数据 loadData:加载本地数据,旧的行将被移除userPermissionGrid.datagrid("loadData",[]);//打开弹出框(居中)editDialog.dialog("center").dialog("open");},//保存save() {var url = "/role/save";//获到id的值var roleId = $("#roleId").val();if (roleId) {url = "/role/update?cmd=_upd_";}//easyui的formeditForm.form('submit', {//提交路径url: url,//提交前的操作 param这个参数加的属性都会向后台提示onSubmit: function (param) {//拿到role(左边的grid)中的所有权限var rows = userPermissionGrid.datagrid("getRows");//遍历它,拼接出相应的结构for(var i=0;i<rows.length;i++){var row = rows[i];param[`permissions[${i}].id`] = row.id;}// 做一些检查return $(this).form('validate');},//data : {success:true/false,msg:xxx}success: function (data) {var result = JSON.parse(data);if (result.success) {roleGrid.datagrid("reload");} else {$.messager.alert('错误', `失败了,失败原因::${result.msg}`, "error");}//关闭弹出框xiaji.closeDialog();}});},//修改update() {//获取到选中的那一行数据var row = roleGrid.datagrid("getSelected");//如果没有选中,给出提示后面的代码就不再执行if (!row) {$.messager.alert('警告', '请选中再修改!', 'warning');return;}//清空form中的数据editForm.form("clear");//让密码框失效且隐藏起来$("*[data-edit]").hide();$("*[data-edit] input").validatebox("disable");//修改弹出框TitleeditDialog.dialog('setTitle', "修改");//把结果进行回显editForm.form("load", row);//打开弹出框(居中)editDialog.dialog("center").dialog("open");//回显左边grid的数据//获取当前选中的行的所有权限//必需要拷备一个数组 不然会直接修改原数据var permissions = [...row.permissions];userPermissionGrid.datagrid("loadData",permissions);},//删除del() {//获取选中数据var row = roleGrid.datagrid('getSelected');//如果没有选中给提示 选中就是否确定删除if (!row) {$.messager.alert('警告', '请选中再删除!', 'warning');return;} else {$.messager.confirm('确认', '您确认想要删除记录吗?', function (r) {if (r) {//选是 确定删除$.get("/role/delete", {id: row.id}, function (result) {if (result.success) {roleGrid.datagrid("reload");} else {$.messager.alert('错误', `失败了,失败原因:${result.msg}`, "error");}})}});}},//批量删除delMore() {//获取选中数据var rows = roleGrid.datagrid('getSelections');//如果没有选中给提示 选中就是否确定删除if (rows.length == 0) {$.messager.alert('警告', '请选中再删除!', 'warning');return;} else {$.messager.confirm('确认', '您确认想要删除记录吗?', function (r) {if (r) {//定义变量值for (var i = 0; i < rows.length; i++) {//选是 确定删除$.get("/role/delete", {id: rows[i].id}, function (result) {if (result.success) {roleGrid.datagrid("reload");} else {$.messager.alert('错误', `失败了,失败原因:${result.msg}`, "error");}})}}});}},//添加权限addPermission(index, row) {// index:点的行  row:这行的数据//获取左边grid的所有数据var rows = userPermissionGrid.datagrid("getRows");//循环所有的行,如果重复传,就不执行后面代码for (var o of rows) {if (o.id == row.id) {$.messager.show({title: '提示',msg: '已添加,请勿重复操作!',timeout: 2000,showType: 'slide',style: {right: '',top: document.body.scrollTop + document.documentElement.scrollTop,bottom: ''}});return;}}userPermissionGrid.datagrid("appendRow", row);},//删除权限removePermission(index, row) {userPermissionGrid.datagrid("deleteRow", index);}};//单独获取两个ridvar userPermissionGrid = $('#userPermissionGrid');var allPermissionGrid = $('#allPermissionGrid');//创建当前角色对应的权限(左)griduserPermissionGrid.datagrid({fit: true,fitColumns: true,singleSelect: true,columns: [[{field: 'name', title: '名称', width: 100},{field: 'sn', title: '权限', width: 100},{field: 'url', title: '资源', width: 100}]],onDblClickRow: xiaji.removePermission});//创建当前角色对应的权限(右)gridallPermissionGrid.datagrid({fit: true,url: '/permission/page',fitColumns: true,singleSelect: true,pagination: true,columns: [[{field: 'name', title: '名称', width: 100},{field: 'sn', title: '权限', width: 100},{field: 'url', title: '资源', width: 100}]],onDblClickRow: xiaji.addPermission});//按键扩展支持$(document).bind('keydown', 'del', xiaji.del);$(document).bind('keydown', 'Shift+1', xiaji.add);$(document).bind('keydown', 'Shift+2', xiaji.update);$(document).bind('keydown', 'Shift+3', xiaji.delMore);});
    

易用宝项目记录day6-login和权限管理相关推荐

  1. java shirofilter_Spring项目集成ShiroFilter简单实现权限管理

    Shiros是我们开发中常用的用来实现权限控制的一种工具包,它主要有认证.授权.加密.会话管理.与Web集成.缓存等功能.我是从事javaweb工作的,我就经常遇到需要实现权限控制的项目,之前我们都是 ...

  2. 【VUE项目实战】32、权限管理-实现角色列表

    接上篇<31.权限管理-实现权限列表> 上个阶段我们完成了权限管理模块,本篇我们来介绍用户.角色和权限三者的关系,并完成角色管理列表模块. 一.权限管理业务分析 通过权限管理模块,控制不同 ...

  3. Spring Security认证授权练手小项目 腾讯视频VIP权限管理功能

    腾讯视频VIP权限管理 1.项目功能视频演示 2.需求与设计 1.需求 2.功能概要 3.接口设计 3.项目源码结构 4.项目源码下载 5.项目部署 1.部署架构 2.数据库环境准备 3.redis环 ...

  4. python调用手机蓝牙_米家生态出品,易锁宝蓝牙U型锁,让开锁更灵活

    由于工作室的外门是传统老式铁艺门,没办法改指纹锁,只能一直用传统的U型锁来锁住.但是经常出现尴尬的情况就是,到了楼下发现忘带钥匙.再加上最近原本的U型锁出现小问题,开锁不那么顺畅了.所以在换U型锁的时 ...

  5. 复习Java第一个项目学生信息管理系统 04(权限管理和动态挂菜单功能) python简单爬数据实例Java面试题三次握手和四次挥手生活【记录一个咸鱼大学生三个月的奋进生活】016

    记录一个咸鱼大学生三个月的奋进生活016 复习Java(学生信息管理系统04权限管理和动态挂菜单功能) 改写MainFrame的构造方法 新增LoginFrame的验证登录是否成功的代码 新增Logi ...

  6. Android WebView使用及苏宁易付宝支付相关问题

    最近项目中应用到苏宁易付宝支付方式  项目中遇到了一些问题总结如下: 易付宝使用处理的逻辑代码: public class YiFuBaoWebView extends BaseActivity im ...

  7. Java后端落地项目记录

    本篇是一个真实落地项目整个后端开发的记录,记录了我看到和参与的项目从0到1的过程. 目录 一.项目概述 二.项目开发流程层面 三.开发技术层面 四.项目进行期间读书笔记 五.总结 一.项目概述 大概讲 ...

  8. UI-网站首页轮播图、易拉宝、发布在微信公众号的宣传海报的图片设计信息

    UI交互设计 一."新建" 常见的颜色模式: 颜色模式,是将某种颜色表现为数字形式的模型,或者说是一种记录图像颜色的方式.分为:RGB模式.CMYK模式.HSB模式.Lab颜色模式 ...

  9. 菜鸟窝-仿京东淘宝项目学习笔记(二)ToolBar的基本使用

    本篇知识点均来自于菜鸟窝-仿京东淘宝实战项目视频中 今天继续仿京东淘宝项目的学习,第二天,学习ToolBar的基本使用,本篇记录视频中一些重要的笔记 笔记一:ToolBar的一些重要属性 xml st ...

  10. 易订宝 移动营销网络订货平台

    易订宝产品介绍 易订宝订货管理系统是西安维度云网软件技术有限公司积累多年企业信息化软件开发经验,专为贸易型和生产型企业开发的新一代实时网上订货管理平台,该平台基于互联网,实现分销商(经销商/代理商)与 ...

最新文章

  1. NLP新秀prompt跨界出圈,清华刘知远最新论文将它应用到VLM图像端
  2. Elastic 的成功上市:偶然和必然
  3. 声学测试软件手机版_最新手机性能排名:小米84万分拿到第一,iQOO5Pro第五,华为?...
  4. E:VUE 插件 开发与使用 (一)
  5. elementui可编辑单元格_关于遥感解译点室内解译编号的读取编辑方法
  6. express使用JWT和httpOnly cookie进行安全验证
  7. 从内部重启python脚本
  8. 工具使用-----Jmeter教程 简单的压力测试
  9. unity打开excel表格_Unity3D读取之(二)——读取Excel文件内容
  10. MyEclipse出现红色感叹号解决办法
  11. android afinal 框架 finalhttp,【Android实战】Afinal框架的使用大全案例
  12. 中国诞生全球最强量子模拟器 量子计算迈出大步
  13. [存储] Cobar使用文档(可用作MySQL大型集群解决方案)
  14. JNI/NDK入门指南之JNI数据类型,描述符详解
  15. 项目中碰见的错误(三) 对路径的访问被拒绝
  16. Emacs指北(做一个搬运工好累)
  17. jupyter保存py格式
  18. unity实现绳子效果(绳索插件Obi Rope)
  19. 正则表达式中/g的用法
  20. 如何删除word中表格后面的空白页

热门文章

  1. 永磁同步电机的直接转矩控制(二)一一一传统DTC仿真结果分析
  2. ArcGIS土地利用重分类(一)简单的reclass by table方法
  3. 搭建hadoop集群,从安装虚拟机开始直到hadoop成功搭建
  4. VirtualBox安装Windows XP
  5. 【MATLAB统计分析与应用100例】案例015:matlab读取Excel数据,进行值聚类分析
  6. 在计算机中表示一个信息容量的基本单位是,微型计算机中,存储器容量的基本单位是()。...
  7. Gilbert Strang的线性代数课程笔记-第一课
  8. 在Excel中批量生成送货单,按数据类别批量生成产品标签
  9. 一阶惯性环节如何实现跟踪性能与滤波性能共存(二)
  10. 中文核心期刊目录(2014 年版)北大核心目录(第七版)新鲜出炉