引言
进企业实习的学习效率非常之高,分享笔记,希望大家共同进步。
知识点
1. Spring boot
- 面向接口编程
由于Spring boot的自动注入IOC容器的存在,之前对调用接口不是太理解。在JPA中体现比较多,调用JPA接口即可调用方法。
// User.java
public interface UserService{
String getInfo();
}
// UserImpl.java
@Component
public class UserServiceImpl implements UserService{
public String getInfo(){
System.out.println("User");
return "Success";
}
}
// UserController.java
@Controller
public class UserController{
// 自动注入接口的实现类
@Autowired
private UserService userService;
@GetMapping("/getInfo")
public String getUserInfo(){
return userService.getInfo();
}
}
-
面向AOP切面编程
Spring boot中多用注解的形式实现功能增强,利用代理模式实现切面增强,具体原理代码还在学习中… -
传值参数校验(@Valid )
利用javax.validation.Valid 即 @Valid注解来解决参数校验的问题:
// UserVO.java
/*
参数接受类
*/
@Data
public class UserVO{
private Long id;
@NotBlank
@Length(min = 4,max = 12, message = "用户名长度不符合要求!")
private String username;
@NotBlank
@Length(min = 6,max = 18, message = "密码长度范围需要在6-18个范围内!")
private String password;
public User createEntity() {
User user = new User();
BeanUtils.copyProperties(this, user);
return user;
}
}
// UserController.java
@RestController
@RequestMapping("/user")
public class UserController{
// 方法一:手动处理验证错误
@PostMapping("/create")
public String saveUser(@Valid @RequestBody UserVO userVO,BindingResult br){
if (br.hasErrors()){
throw new ValidationException("数据不规范!");
}
return "Success";
}
// 方法二:不进行主动处理,抛出MethodArgumentNotValidException异常
@PostMapping("/create")
public String saveUser(@Valid @RequestBody UserVO userVO){
return "Success";
}
}
// 统一处理异常
// ExerciseExceptionHandler.js
@ControllerAdvice
@Slf4j
@Order(ExerciseExceptionHandler.Order.GLOBAL_PRECEDENCE)
public class ExerciseExceptionHandler {
@ExceptionHandler(ValidationException.class)
@ResponseBody
public ResponseMessage handleValidationException(ValidationException be) {
HashMap<String,Object> resp = new HashMap<>();
resp.put("status",500);
resp.put("msg",be.getMessage());
return resp;
}
}
- JWT (json web token)
网站系统单点登录解决方案,与其说它是方案,不如说是标准。相对于Session来说,其不申请内存空间,自带信息。基于这一特点,便可以做到跨域访问,token接收者只需要用加密盐key去解密进行身份核实即可。
其分为三段内容:
- Header
- Payload
- Signature
jwt = Base64url(Header).Base64url(Payload).Signature
Signature = HS256(Header.Payload)
// Header
{
"alg":"HS256", // 签名算法
"typ":"JWT" //类型
}
// Payload
{
// 规范中的字段
"jti": //唯一标识
"sub": //该JWT的主题
"aud": //该JWT面向的用户
"iss": //该JWT的签发者
"iat": //该JWT的签发时间
"exp": //该JWT的过期时间
"nbf": //该JWT在该时间之前不能被接收处理
// data数据部分,自定义
"username":
... ...
}
// Signature 加盐加密前两段数据
先给出一个小demo,之后会完善:
<!--pom.xml -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
#application.yml
jwt-util:
subject: jwt
issuer: pengzhou
secretKey: pengzhou2019pwd
workTime: 3600000
// JwtUtil.java
/**
* JWT 令牌(token)发放工具
* @author Somebody
* @date 2019/8/13 15:35
*/
@Data
@Component
@ConfigurationProperties(prefix = "jwt-util")
public class JwtUtil {
private String subject;
private String issuer;
private String secretKey;
private Long workTime;
public String createJwtToken(String username){
SignatureAlgorithm signatureAlgorithm1 = SignatureAlgorithm.HS256;
Date now = new Date();
Long nowDate = now.getTime();
// 构造token的头部信息(Header)
Map<String,Object> tokenHeader = new HashMap<>();
tokenHeader.put("alg",signatureAlgorithm1.getValue());
tokenHeader.put("typ", "JWT");
// 构造payload和Signature
JwtBuilder builder = Jwts.builder().setHeader(tokenHeader)
.claim("username",username)
.setSubject(subject)
.setIssuer(issuer)
.setIssuedAt(now)
.setExpiration(new Date(nowDate+workTime))
.signWith(signatureAlgorithm1,secretKey);
return builder.compact();
}
public Claims parseToken(String token){
Jws<Claims> jws = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token);
return jws.getBody();
}
}
2.Vue.js相关
- javascript -ES6
// ES6 导入 和 导出
// ES6 语法在webpack打包时需要使用babel-core babel-load等相关组件进行转化
import 模块名 form '模块标识符'
export default{
...
}
或
export 暴露成员
export const model = () => {
...
}
// Node 导入 和 导出
var 名称 = require('模块标识符')
module.exports 和 export 暴露成员
- 孤儿语法的使用
// 正常版
import App from './App.vue'
new Vue({
el: 'app',
render: function (createElements){
// createElements 是一个方法,调用它可以把指定的组件模板渲染为html结构
return createElements(App);
}
})
// ES6孤儿进化版
import App from './App.vue'
new Vue({
el: 'app',
render: c => c(App)
})
- Element-ui 表单验证
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="密码" prop="pass">
<el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input v-model.number="ruleForm.age"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
<script>
export default {
data() {
var checkAge = (rule, value, callback) => {
if (!value) {
return callback(new Error('年龄不能为空'));
}
setTimeout(() => {
if (!Number.isInteger(value)) {
callback(new Error('请输入数字值'));
} else {
if (value < 18) {
callback(new Error('必须年满18岁'));
} else {
callback();
}
}
}, 1000);
};
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'));
} else {
if (this.ruleForm.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass');
}
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.ruleForm.pass) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
return {
ruleForm: {
pass: '',
checkPass: '',
age: ''
},
rules: {
pass: [
{ validator: validatePass, trigger: 'blur' }
],
checkPass: [
{ validator: validatePass2, trigger: 'blur' }
],
age: [
{ validator: checkAge, trigger: 'blur' }
]
}
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
alert('submit!');
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
}
</script>
利用rules来做验证,rules中也可以写正则表达式。
data(){
return {
dialogRules: {
loseEfficacyReason: [
{ required: true, message: '请输入原因', trigger: 'blur' },
{ min: 2, message: '请输入不少于2个字符', trigger: 'blur' },
{ pattern: /^[A-Za-z0-9\u4e00-\u9fa5]+$/, message: '不允许输入空格等特殊符号' }
]
}
}
}
- Vuex
不多写总结了,具体看官方文档。
3.原型设计相关
- 重点要求
对需求的分析考虑要非常全面! - 工具
Balsamiq Mockups 3 - 注意点
- 一致性要求,包括内容、位置、对齐方式:
表格中通常文字左对齐,数字右对齐;
确认框,取消在左边,确定在右边; - 网页的左右留白;
- 原型设计时,需要结合好数据字段,要将字段全部展现出来,不能省略;
- 吐槽一句:我点点点NM的整个网页~
解决方案
1. sql语句like字段参数带有“%_”保留关键字符的问题
- 问题起因:
# 例:
Select * From User Where username Like Concat("%", :username, "%");
:username为用户输入参数,当用户输入%或_时,sql会将%或_当作保留字,%匹配任意字符,_则为单个字符占位符,最终导致查询结果不是设想的结果。
- 解决方案:
sql在语句层面提供了解决方案,即是利用escape来自定义转译符号,但要注意的是escape只能在like子句中起作用。
Select * From User Where username Like "%/%/_%" escape "/";
上面这句sql的最终效果就是查找 username中包含 “%_” 这一字符串的用户信息,另外有多个like字句时,需要多次写escape。
Select *From User Where username Like "%/%/_%" escape "/" or email Like "%/_ty%" escape "/";
2. 字符串正则匹配并插入字符的问题
- 问题起因:
针对上一个问题,需要对拼接入sql语句like字段的参数进行处理,在参数中的%和_符号前添加“/”转义符。即对字符串进行查询替换,这里有两个解决方案: - 解决方案:
// 方法一:
public static void main(String[] args) {
String usernameLike = "%ad%_asd%";
usernameLike.replaceAll("%","/").replaceAll("_","/");
}
// 方法二:
public static void main(String[] args) {
StringBuilder usernameLike = new StringBuilder("%ad%_asd%");
Pattern pattern = Pattern.compile("[_%]");
Matcher matcher = pattern.matcher(usernameLike);
Stack<Integer> indexSk = new Stack<>();
while(matcher.find()) {
indexSk.push(matcher.start());
}
while(!indexSk.empty()){
usernameLike.insert(indexSk.pop(),"/");
}
}
需要在代码简洁性和性能上做一个取舍。