【开源项目--稻草】Day03

【开源项目--稻草】Day03

  • 1. 续Spring-Security
    • 1.1 自定义登录界面
  • 2. 用户注册
    • 2.1 将注册页面显示
    • 2.2 编写控制器进行测试
    • 2.3 编写注册业务逻辑
    • 2.4 注册功能的收尾
  • 3. VUE
    • 3.1 VUE的基本使用
      • 3.1.1 什么是VUE
    • 3.2 使用VUE+Ajax完善稻草问答的注册功能

1. 续Spring-Security

1.1 自定义登录界面

如果想在用户登录时用我们自己的登录页面代替Spring-Security提供的登录页面

需要进行如下配置

步骤1:

登录页面是视图模板引擎生成的,所以需要引入Thymeleaf的依赖

子项目的pom.xml文件

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity5</artifactId></dependency>

步骤2:

将static文件夹中的login.html
复制到templates文件夹下
需要注意
现在login.html提交的路径是/login
用户名和密码输入框的name是username和password
这两个名字也是Spring-Security约定的不要改!!
我们需要写一个控制器来访问显示这个页面
这个控制器不输于任何实体类,新建一个SystemController

@RestController
public class SystemController {// 显示登录页面的方法@GetMapping("/login.html")public ModelAndView loginForm(){//ModelAndView("login");对应的是resources/templates/login.htmlreturn new ModelAndView("login");}
}

步骤3:
要对login.html进行放行

要配置登录时的各种信息

要配置登出时的各种信息

SecurityConfig类中编写

 @Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests()//对当前全部请求进行授权.antMatchers("/index.html","/img/*","/js/*","/css/*","/bower_components/**","/login.html")//设置路径.permitAll()//允许全部请求访问上面定义的路径//其它路径需要全部进行表单登录验证.anyRequest().authenticated().and().formLogin().loginPage("/login.html").loginProcessingUrl("/login").failureUrl("/login.html?error").defaultSuccessUrl("/index.html").and().logout().logoutUrl("/logout").logoutSuccessUrl("/login.html?logout");}

方法说明:

1.csrf().disable():关闭防跨域攻击功能,不关闭容易发生错误
2.loginPage:指定登录页面路径
3.loginProcessingUrl:指定表单提交的路径
4.failureUrl:指定登录失败时的路径
5.defaultSuccessUrl:指定登录成功时的路径
6.logout():表示开始配置登出时的内容
7.logoutUrl:指定出的路径(当页面有这个请求时,Spring-Security去执行用户登出操作)
8.logoutSuccessUrl:指定登出成功之后显示的页面

2. 用户注册

每个网站都需要用户注册的功能
页面如下图
在这里插入图片描述
1.获得邀请码(开发过程是从数据库获得,运营时向老师索取)
2.通过登录页上的注册连接显示注册页面
3.向服务器请求注册页并显示到浏览器
4.注册页面填写信息并提交表单
5.服务器接收到表单信息,控制层调用业务逻辑层执行注册操作
6.业务层执行连库操作新增之前验证邀请码
7.邀请码验证通过在执行数据库新增操作
8.返回新增操作的运行结果
9.根据结果反馈到控制层,有异常就报异常
10.控制器将注册结果信息使用JSON返回给浏览器
11.浏览器中局部刷新页面,将注册结果显示给用户

2.1 将注册页面显示

步骤1:

复制static文件夹中的register.html页面到templates文件夹

步骤2:

编写控制器SystemController类中添加方法

	// 显示注册页面的方法@GetMapping("/register.html")public ModelAndView register(){return new ModelAndView("register");}

步骤3:

SecurityConfig类中放行register.html

http.csrf().disable().authorizeRequests()//对当前全部请求进行授权.antMatchers("/index.html","/img/*","/js/*","/css/*","/bower_components/**","/login.html","/register.html"  //放行在这个!!!!!!)//设置路径.permitAll()//允许全部请求访问上面定义的路径//其它路径需要全部进行表单登录验证.anyRequest().authenticated().and().formLogin().loginPage("/login.html").loginProcessingUrl("/login").failureUrl("/login.html?error").defaultSuccessUrl("/index.html").and().logout().logoutUrl("/logout").logoutSuccessUrl("/login.html?logout");

2.2 编写控制器进行测试

我们先编写一个简单的控制器代码接收表单的信息,并返回内容
在页面上显示

步骤1:

表单提交的5个属性创建一个Vo类接收代码如下

@Data
public class RegisterVo implements Serializable {private String inviteCode;private String phone;private String nickname;private String password;private String confirm;
}

步骤2:

上面步骤1中的实体类能接收表单发送过来的信息

但是我们控制器处理完成后,想返回Json格式的对象给JS,也需要一个实体类

这个实体类最好能够通用于所有业务

现在行业中流行使用一个"R"类来返回JSON格式信息

这个R类中主要包含3个属性

1.状态码

2.状态消息

3.实体(控制器查询出的任何内容)

创建R类(代码无需掌握,会使用即可)

@Data
@Accessors(chain = true)
public class R<T> implements Serializable {/** 200 OK - [GET]:服务器成功返回用户请求的数据 */public static final int OK = 200;/** 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 */public static final int CREATED = 201;/** 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务) */public static final int ACCEPTED = 202;/** 204 NO CONTENT - [DELETE]:用户删除数据成功。 */public static final int NO_CONTENT = 204;/** 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作。*/public static final int INVALID_REQUEST = 400;/** 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。 */public static final int UNAUTHORIZED = 401;/** 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。*/public static final int FORBIDDEN = 403;/** 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作。 */public static final int NOT_FOUND = 404;/** 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。*/public static final int GONE = 410;/** 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。 */public static final int UNPROCESABLE_ENTITY = 422;/** 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。 */public static final int INTERNAL_SERVER_ERROR = 500;private int code;private String message;private T data;/*** 服务器成功返回用户请求的数据* @param message 消息*/public static R ok(String message){return new R().setCode(OK).setMessage(message);}/*** 服务器成功返回用户请求的数据* @param data 数据*/public static R ok(Object data){return new R().setMessage("OK").setCode(OK).setData(data);}/*** 用户新建或修改数据成功。*/public static R created(String message){return new R().setCode(CREATED).setMessage(message);}/*** 表示一个请求已经进入后台排队(异步任务)*/public static R accepted(String message){return new R().setCode(ACCEPTED).setMessage(message);}/*** 用户删除数据成功*/public static R noContent(String message){return new R().setCode(NO_CONTENT).setMessage(message);}/*** 用户发出的请求有错误,服务器没有进行新建或修改数据的操作。*/public static R invalidRequest(String message){return new R().setCode(INVALID_REQUEST).setMessage(message);}/*** 表示用户没有权限(令牌、用户名、密码错误)*/public static R unauthorized(String  message){return new R().setCode(UNAUTHORIZED).setMessage(message);}/*** 登录以后,但是没有足够权限*/public static R forbidden(){return new R().setCode(FORBIDDEN).setMessage("权限不足!");}/*** 用户发出的请求针对的是不存在的记录,服务器没有进行操作。*/public static R notFound(String message){return new R().setCode(NOT_FOUND).setMessage(message);}/*** 用户请求的资源被永久删除,且不会再得到的。*/public static R gone(String message){return new R().setCode(GONE).setMessage(message);}/*** 当创建一个对象时,发生一个验证错误。*/public static R unproecsableEntity(String message){return new R().setCode(UNPROCESABLE_ENTITY).setMessage(message);}/*** 将异常消息复制到返回结果中*/public static R failed(ServiceException e){return new R().setCode(e.getCode()).setMessage(e.getMessage());}/*** 服务器发生错误,用户将无法判断发出的请求是否成功。*/public static R failed(Throwable e){return new R().setCode(INTERNAL_SERVER_ERROR).setMessage(e.getMessage());}
}

步骤3:

上面两个步骤分别解决了控制器的参数和返回值的问题,

下面我们就测试一个控制器代码,观察是否能够获得参数信息,并返回

SystemController中编写代码

@RestController
@Slf4j//启动日志功能!
public class SystemController {//省略其它方法....@PostMapping("/register")public R registerStudent(RegisterVo registerVo){System.out.println(registerVo);log.debug("得到信息为:{}",registerVo);return R.created("注册成功!");}
}

步骤4:

配置/register请求的放行

SecurityConfig代码中

 http.csrf().disable().authorizeRequests()//对当前全部请求进行授权.antMatchers("/index.html","/img/*","/js/*","/css/*","/bower_components/**","/login.html","/register.html","/register"  //放行注册业务!!!!!!)//设置路径.permitAll()//允许全部请求访问上面定义的路径//其它路径需要全部进行表单登录验证.anyRequest().authenticated().and().formLogin().loginPage("/login.html").loginProcessingUrl("/login").failureUrl("/login.html?error").defaultSuccessUrl("/index.html").and().logout().logoutUrl("/logout").logoutSuccessUrl("/login.html?logout");

步骤5:

配置日志等级

在控制器的代码中我们启用了日志

需要配置debug等级才能显示在控制台

application.properties文件

logging.level.cn.tedu.straw.portal.mapper=trace
logging.level.cn.tedu.straw.portal=debug

2.3 编写注册业务逻辑

步骤1:

注册业务逻辑属于User表

所以在IUserService接口中新建注册方法

// 用户注册的方法(现在是针对学生注册)
void registerStudent(RegisterVo registerVo);

步骤2:

在IUserService的实现类UserServiceImpl类中重写接口的方法

在方法中排定业务逻辑顺序

 @Overridepublic void registerStudent(RegisterVo registerVo) {//判断registerVo非空//根据输入的邀请码查询班级,验证邀请码有效性//验证数据库中是否已经注册过输入的用户名(手机号)//User对象的赋值(将表单中的值和一些默认值确定后)//执行User新增//验证新增结果//将新增的用户赋予学生的角色(新增user_role的关系表)//验证关系表新增结果}

步骤3:

编写判定以及验证时需要的自定义业务异常类

这个类和R类相同也不需要掌握代码,只需要掌握用法

package cn.tedu.straw.portal.service;import cn.tedu.straw.portal.vo.R;public class ServiceException extends RuntimeException{private int code = R.INTERNAL_SERVER_ERROR;public ServiceException() { }public ServiceException(String message) {super(message);}public ServiceException(String message, Throwable cause) {super(message, cause);}public ServiceException(Throwable cause) {super(cause);}public ServiceException(String message, Throwable cause,boolean enableSuppression, boolean writableStackTrace) {super(message, cause, enableSuppression, writableStackTrace);}public ServiceException(int code) {this.code = code;}public ServiceException(String message, int code) {super(message);this.code = code;}public ServiceException(String message, Throwable cause,int code) {super(message, cause);this.code = code;}public ServiceException(Throwable cause, int code) {super(cause);this.code = code;}public ServiceException(String message, Throwable cause,boolean enableSuppression, boolean writableStackTrace, int code) {super(message, cause, enableSuppression, writableStackTrace);this.code = code;}public int getCode() {return code;}/** 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作。*/public static ServiceException invalidRequest(String message){return new ServiceException(message, R.INVALID_REQUEST);}/** 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作。 */public static ServiceException notFound(String message){return new ServiceException(message, R.NOT_FOUND);}/** 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。*/public static ServiceException gone(String message){return new ServiceException(message, R.GONE);}/** 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。 */public static ServiceException unprocesabelEntity(String message){return new ServiceException(message, R.UNPROCESABLE_ENTITY);}
}

步骤4:

完成UserServiceImpl类的编写

@Service
@Slf4j//添加了log4j的支持
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {@AutowiredUserMapper userMapper;@Overridepublic UserDetails getUserDetails(String username) {// 此方法代码略}@AutowiredClassroomMapper classroomMapper;@AutowiredUserRoleMapper userRoleMapper;BCryptPasswordEncoder passwordEncoder=new BCryptPasswordEncoder();@Overridepublic void registerStudent(RegisterVo registerVo) {//判断registerVo非空if(registerVo==null){//如果信息是空则发生异常//这里的异常逻辑是我们编写的项目发生的,不是系统异常//所以这里以及以后的方法中都需要抛出自定义的异常throw ServiceException.unprocesabelEntity("表单数据为空");}//根据输入的邀请码查询班级,验证邀请码有效性QueryWrapper<Classroom> queryWrapper=new QueryWrapper<>();queryWrapper.eq("invite_code",registerVo.getInviteCode());Classroom classroom=classroomMapper.selectOne(queryWrapper);log.debug("邀请码对应的班级为:{}",classroom);if(classroom==null){throw ServiceException.unprocesabelEntity("邀请码错误!");}//验证数据库中是否已经注册过输入的用户名(手机号)//用户名查询用户对象User u=userMapper.findUserByUsername(registerVo.getPhone());if(u!=null){//用户已存在throw ServiceException.unprocesabelEntity("手机号已经注册!");}//User对象的赋值(将表单中的值和一些默认值确定后)User user=new User();user.setUsername(registerVo.getPhone());user.setPhone(registerVo.getPhone());user.setNickname(registerVo.getNickname());//用户输入的是明文密码,数据库保存的是带算法ID的加密结果!user.setPassword("{bcrypt}"+passwordEncoder.encode(registerVo.getPassword()));user.setClassroomId(classroom.getId());user.setCreatetime(LocalDateTime.now());user.setEnabled(1);user.setLocked(0);//执行User新增int num=userMapper.insert(user);//验证新增结果if(num!=1) {throw new ServiceException("服务器忙,稍后再试");}//将新增的用户赋予学生的角色(新增user_role的关系表)UserRole userRole=new UserRole();userRole.setUserId(user.getId());userRole.setRoleId(2);num=userRoleMapper.insert(userRole);//验证关系表新增结果if(num!=1) {throw new ServiceException("服务器忙,稍后再试");}}
}

步骤5:

编写测试类

@AutowiredIUserService userService;@Testpublic void testUserService(){RegisterVo registerVo=new RegisterVo();registerVo.setPhone("13333113131");registerVo.setNickname("大树");registerVo.setInviteCode("JSD1912-876840");registerVo.setPassword("123456");registerVo.setConfirm("123456");userService.registerStudent(registerVo);System.out.println("complate!");}

2.4 注册功能的收尾

    @AutowiredIUserService userService;@PostMapping("/register")public R registerStudent(RegisterVo registerVo){System.out.println(registerVo);log.debug("得到信息为:{}",registerVo);try{userService.registerStudent(registerVo);return R.created("注册成功!");}catch (ServiceException e){log.error("注册失败",e);return R.failed(e);}}

3. VUE

3.1 VUE的基本使用

3.1.1 什么是VUE

也是一个js为基础的前端框架

提供了一套前端信息和服务器信息交互的一种方式

这种方式要比以前的信息交互方式简单

一般情况下,程序要结合JQuery的ajax操作和Vue的功能完成前后端信息交互

使用准备

Idea添加插件
在这里插入图片描述
编写html文件

static文件夹下创建一个测试Vue的页面vue.html

这个页面项目中不使用,就是测使用

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!-- 添加VUE的支持 --><script src="bower_components/vue/dist/vue.js"></script>
</head>
<body>
<div id="app"><p v-text="message">VUE演示</p><input type="text" v-model="content"><button type="button" v-on:click="hello">按钮</button>
</div>
</body>
<script>//使用Vuelet app=new Vue({el:"#app",data:{message:"Vue发送的文字!",content:"输入框的内容"},methods:{hello:function(){console.log(this.content);//this.content=this.content+"!";}}});
</script>
</html>

Vue功能的强大之处在于信息实时同步的双向绑定

在这里插入图片描述

3.2 使用VUE+Ajax完善稻草问答的注册功能

修改register.html代码

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="renderer" content="webkit"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><title>稻草FAQ注册</title><link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css"><link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css"><link rel="stylesheet" href="bower_components/plugins/css/vueAlert.css"><link rel="stylesheet" href="css/login.css"><script src="bower_components/jquery/dist/jquery.min.js" ></script><script src="bower_components/bootstrap/dist/js/bootstrap.min.js" ></script><script src="bower_components/vue/dist/vue.js"></script>
</head>
<body class="bg-light"><div class="container-fluid"><div class="row"><div class="mx-auto mt-5" style="width: 400px"><div class="alsrtInfo" style="display: none"><div class="profPrompt_test" ></div></div><h2 class="text-center">达内稻草问答系统</h2><div class="bg-white p-4" id="app"><p class="text-center"><b>注册新用户</b></p><div id="error" class="alert alert-danger" style="display: none"><i class="fa fa-exclamation-triangle"></i> <span >邀请码错误!</span></div><!--v-on:submit.prevent表示绑定一个方法 ,.prevent阻止表单提交 --><form action="/register" method="post"v-on:submit.prevent="register"><div class="form-group has-icon"><input type="text" name="inviteCode" class="form-control" placeholder="请输入邀请码"required="required" v-model="inviteCode"><span class="fa fa-barcode form-control-icon"></span></div><div class="form-group has-icon"><input type="tel" name="phone" class="form-control" placeholder="请输入手机号"pattern="^\d{11}$" required="required" v-model="phone" ><span class=" fa fa-phone form-control-icon"></span></div><div class="form-group has-icon"><input type="text" name="nickname" class="form-control" placeholder="请设置昵称,字数为2-20之间"pattern="^.{2,20}$" required="required" v-model="nickname" ><span class="fa fa-user form-control-icon"></span></div><div class="form-group has-icon"><input type="password" name="password" class="form-control" placeholder="设置密码6-20个字母、数字、下划线"required="required" pattern="^\w{6,20}$" v-model="password"  ><span class="fa fa-lock form-control-icon"></span></div><div class="form-group has-icon"><input type="password" name="confirm" class="form-control" placeholder="请再次输入密码"required="required"  v-model="confirm"><span class="fa fa-lock form-control-icon"></span></div><button type="submit" class="btn btn-primary btn-block btn-flat" >注册</button></form><a href="login.html" class="text-center d-inline-block mt-3">已有账号,立即登录</a></div><!-- /.form-box --></div></div>
</div>
</body>
<script src="js/utils.js"></script>
<script src="js/register.js"></script>
</html>

修改static/js/register.js代码

let app = new Vue({el:'#app',data:{inviteCode:'',phone:'',nickname:'',password:'',confirm:''},methods:{register:function () {console.log('Submit');let data = {inviteCode: this.inviteCode,phone: this.phone,nickname: this.nickname,password: this.password,confirm: this.confirm}console.log(data);if(data.password !== data.confirm){return;}$.ajax({url:"/register",method: "POST",data: data,success: function (r) {console.log(r);if(r.code == CREATED){console.log("注册成功");console.log(r.message);}else{console.log(r.message);}}});}}
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/55749.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot+vue超市进销存管理系统_91crh

表名&#xff1a;zengsongxinxi 功能&#xff1a;赠送信息 字段名称 类型 长度 字段说明 主键 默认值 id bigint 主键 主键 addtime timestamp 创建时间 CURRENT_TIMESTAMP shangpinmingcheng varchar 200 商品名称…

如何在IDEA中启动多个SpringBoot服务实例

文章目录 一、前言&#xff1a;二、IDEA版本&#xff1a;三、Allow parallel run 模式&#xff1a;四、解决方案&#xff1a; 一、前言&#xff1a; 在IDEA中&#xff0c;"Allow parallel run"是一个配置选项&#xff0c;用于指定是否允许并行运行多个相同的启动配置…

uniapp使用阿里图标

效果图&#xff1a; 前言 随着uniApp的深入人心&#xff0c;我司也陆续做了几个使用uniapp做的移动端跨平台软件&#xff0c;在学习使用的过程中深切的感受到了其功能强大和便捷&#xff0c;今日就如何在uniapp项目中使用阿里字体图标的问题为大家献上我的一点心得&#xff0…

triangles parallel lines

三角形与平行线 如何把现实问题或者抽象问题图形化呢。 梯形面积&#xff1a;四边形面积是如何从三角形面积转换而来的呢&#xff0c;数学里面作图其实蛮重要的&#xff0c;作图的好坏关系到是否能够更加直观明了展现关系&#xff0c;例如为什么有时候三角形&#xff0c;梯形要…

LNMP及论坛搭建(第一个访问,单节点)

LNMP&#xff1a;目前成熟的一个企业网站的应用模式之一&#xff0c;指的是一套协同工作的系统和相关软件 能够提供静态页面服务&#xff0c;也可以提供动态web服务&#xff0c;LNMP是缩写 L&#xff1a;指的是Linux操作系统。 N&#xff1a;指的是nginx&#xff0c;nginx提…

react icon ant简单使用

refer&#xff1a; 文字提示 Tooltip - Ant Design 1.首先保证已经引入了Ant 2.在组件&#xff08;页面&#xff09;引入tooltip import { Form, Tooltip } from antd; 3.在合适的位置使用tooltip&#xff1a; <span>寿命 <Tooltip title"这是寿命的说明&quo…

Vue系列第七篇:Element UI之el-main,el-table,el-dialog,el-pagination,el-breadcrumb等控件使用

本篇实现主页面功能&#xff0c;包括主页面排版布局&#xff0c;学生管理模块实现&#xff0c;后台接口实现等功能。 目录 1.运行效果 1.1登录页面 1.2主页面 1.3学生管理 - 信息列表 1.4学生管理 - 信息管理 1.5学生管理 - 作业列表 1.6学生管理 - 作业管理 2.前端代码…

并查集练习 — 岛屿问题(二)

题目&#xff1a; 同样是岛的问题&#xff0c;但是参数有所变化&#xff0c;一共3个参数&#xff0c;m、n、int[][] position。根据position&#xff0c;求出每一步的岛屿的数量。 代表的意思是&#xff1a;m * n是二维数组的行和列&#xff0c;通过 m * n可以构建一个值都为0的…

gateway过滤器没生效,特殊原因

看这边文章的前提&#xff0c;你要会gateway&#xff0c;知道过滤器怎么配置&#xff1f; 直接来看过滤器&#xff0c;局部过滤器 再来看配置 请求路径 http://127.0.0.1:8080/appframework/services/catalog/catalogSpecials.json?pageindex1&pagesize10&pkidd98…

【雕爷学编程】MicroPython动手做(28)——物联网之Yeelight 3

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

微软研究院展示Project Rumi项目;参数高效微调(PEFT)

&#x1f989; AI新闻 &#x1f680; 微软研究院展示Project Rumi项目&#xff0c;通过多模态方法增强人工智能理解能力 摘要&#xff1a;微软研究院展示了Project Rumi项目&#xff0c;该项目通过结合文本、音频和视频数据&#xff0c;并采用多模态副语言提示的方法&#xf…

医疗器械研发中的可用性工程实践(一)

致读者&#xff1a;以前看《楚门的世界》&#xff0c;《蝴蝶效应》&#xff0c;《肖申克的救赎》&#xff0c;《教父》&#xff0c;《横道世之介》&#xff0c;《老友记》&#xff0c;一个人的一生匆匆。作为平凡人就是历史大河中的浪花&#xff0c;顺势而为&#xff0c;起起伏…