0%

1 C盘满

在你想要存放数据的盘符下创建文件夹,假设为E:\Google Chrome\User Data
把已经存在的User Data数据复制到E:\Google Chrome\中开始->附件->命令提示符(右键以管理员身份运行)输入CD C:\Users\用户名\AppData\Local\Google\Chrome
输入RMDIR /S “User Data”,提示是否删除输入Y
输入MKLINK /J “User Data” “E:\Google\Chrome”
重启浏览器,大功告成。

rmdir /S "C:\Users\16325\AppData\Local\Microsoft\Edge\User Data"
mklink /J "C:\Users\16325\AppData\Local\Microsoft\Edge" "F:\Cache\Edge"

1 什么是JWT

JWT (JSON Web Token) 是目前最流行的跨域认证解决方案,是一种基于 Token 的认证授权机制。 从 JWT 的全称可以看出,JWT 本身也是 Token,一种规范化之后的 JSON 结构的 Token。

JWT 自身包含了身份验证所需要的所有信息,因此,我们的服务器不需要存储 Session 信息。这显然增加了系统的可用性和伸缩性,大大减轻了服务端的压力。

可以看出,JWT 更符合设计 RESTful API 时的「Stateless(无状态)」原则

并且, 使用 JWT 认证可以有效避免 CSRF 攻击,因为 JWT 一般是存在在 localStorage 中,使用 JWT 进行身份验证的过程中是不会涉及到 Cookie 的。

2 JWT由哪些部分组成

JWT 本质上就是一组字串,通过(.)切分成三个为 Base64 编码的部分:

  • Header(头部) : 描述 JWT 的元数据,定义了生成签名的算法以及 Token 的类型。Header 被 Base64Url 编码后成为 JWT 的第一部分。

  • Payload(载荷) : 用来存放实际需要传递的数据,包含声明(Claims),如sub(subject,主题)、jti(JWT ID)。Payload 被 Base64Url 编码后成为 JWT 的第二部分。

  • Signature(签名):服务器通过 Payload、Header 和一个密钥(Secret)使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。生成的签名会成为 JWT 的第三部分。

JWT 通常是这样的:xxxxx.yyyyy.zzzzz

3 如何基于JWT进行身份认证

在基于 JWT 进行身份验证的的应用程序中,服务器通过 Payload、Header 和 Secret(密钥)创建 JWT 并将 JWT 发送给客户端。客户端接收到 JWT 之后,会将其保存在 Cookie 或者 localStorage 里面,以后客户端发出的所有请求都会携带这个令牌。

简化后的步骤如下:

  1. 用户向服务器发送用户名、密码以及验证码用于登陆系统。

  2. 如果用户用户名、密码以及验证码校验正确的话,服务端会返回已经签名的 Token,也就是 JWT。

  3. 用户以后每次向后端发请求都在 Header 中带上这个 JWT 。

  4. 服务端检查 JWT 并从中获取用户相关信息。

1 智能素材生成

[!question]
需求的价值开始讲,然后分析问题再给出解决方案

解决了什么问题,怎么解决的,难点,思考点是啥(方案选型)、其他方案对比

广告投放包括素材,定向和出价

  • 素材用来表达和展示商品,吸引目标用户

  • 定向:广告投放给哪些人

代理制作素材流程长(多次审核->法规、隐私数据)、缺乏与商品之间的关联、制作效率低

在媒体看到感兴趣的广告时,有这样的经历,看到的广告商品点击进入应用后,有时候很难找到那个商品,这便是承接要做的事情。

新老流程对比素材用来展示商品

  • 代理制作素材流程长

使用了什么方案,解决了什么问题

  • 生成素材质量和准确性:代理制作素材采用通投文案和通用模板

素材质量好坏评估指标:

  • 点击率

  • 转换成本

  • 拉新成功率

描述项目的技术挑战和你是如何解决的

异步提交素材生产任务,调用素材生成服务可能失败

[!question] 消息队列解决什么场景

提交素材生产任务后,拿到素材生成任务ID,异步进行素材生产。作为消费方,通过消息队列监听素材生产状态,根据素材生成任务ID更新素材状态

  • 消息重复

[!question] #{} 和 ${} 的区别是什么?

  • ${}是 Properties 文件中的变量占位符,它可以用于标签属性值和 sql 内部,属于原样文本替换,可以替换任意内容,比如${driver}会被原样替换为com.mysql.jdbc. Driver
  • #{}是 sql 的参数占位符,MyBatis 会将 sql 中的#{}替换为? 号,在 sql 执行前会使用 PreparedStatement 的参数设置方法,按序给 sql 的? 号占位符设置参数值,比如 ps.setInt(0, parameterValue),#{item.name} 的取值方式为使用反射从参数对象中获取 item 对象的 name 属性值,相当于 param.getItem().getName()
  • 符号$,它会把参数值直接进行替换,而不会进行预编译(如果使用占位符#,就会进行预编译,从而可以防止SQL注入

1 MyBatis避免SQL注入

2 SQL语句映射模式

基于xml

<mapper namespace="mapper.UserMapper">
<!--结果集映射(ORM)-->
<resultMap id="userResultMap" type="entity.UserEntity">
<!-- propery表示UserEntity属性名,column表示tb_user表字段名-->
<id property="id" column="id" />
<result property="userName" column="user_name" />
<result property="password" column="password" />
<result property="name" column="name" />
<result property="age" column="age" />
<result property="sex" column="sex" />
<result property="birthday" column="birthday" />
<result property="created" column="created" />
<result property="updated" column="updated" />
</resultMap>

<!--select查询语句 id表示接口方法名 resultMap表示引用结果集映射-->
<select id="selectUserByAge" resultMap="userResultMap">
select * from tb_user where age > #{age}
</select>
</mapper>

基于注解

@Select("select * from tb_user where age > #{age}")
@Results(value = {
@Result(property = "id",column = "id",id = true),
@Result(property = "userName",column = "userName"),
@Result(property = "password",column = "password"),
@Result(property = "name",column = "name"),
@Result(property = "sex",column = "sex"),
@Result(property = "age",column = "age"),
@Result(property = "birthday",column = "birthday"),
@Result(property = "created",column = "created"),
@Result(property = "updated",column = "updated")
})
public List<UserEntity> selectUserByAge(@Param("age") int age);