SpringMVC
@GetMapping
注释将 HTTP GET 请求映射到特定的处理程序方法。 它是一个组合的注释,用作@RequestMapping(method = RequestMethod.GET)
的快捷方式。@GetMapping
将从 GET 请求到index()
方法的/
根路径映射。 它返回纯文本
@PostMapping
注释将 HTTP POST 请求映射到特定的处理程序方法。 它是一个组合的注释,用作@RequestMapping(method = RequestMethod.POST)
的快捷方式。@PostMapping
将createPost()
方法映射到valueURL。
String类的format()方法用于创建格式化的字符串以及连接多个字符串对象。熟悉C语言应该记得C语言的sprintf()方法,两者有类似之处。format()方法有两种重载形式。
SpringSecurity
WebSecurityConfigureAdapter
提供一个用于创建一个Websecurityconfigurer实例方便的基类,允许自定义重写其方法。这里重写了configure方法。
1.permitAll()是指允许任何人访问的方法,包括匹配css js fonts路径的URL及index页面
2.所有匹配users的URL请求需要用户进行身份验证。
3.fromLogin()表明这是个基于表单的身份验证,指明了登录的URL路径以及登录失败的URL
There is no PasswordEncoder mapped for the id "null"解决方法:
这是由于Spring security5中新增加了加密方式,并把原有的spring security的密码存储格式改了。
程序出错的原因: 前端传过来密码后,程序会查找被 花括号"{}"包括起来的id ,以此来确定后面的密码怎么进行加密,而我们在前面并没有按该格式进行处理,这就导致找不到id,就报错了。
解决方法:
只需要对前端传过来的密码进行某种方式加密,就可以了,而官方推荐的是使用bcrypt的加密方式
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication() // 认证信息存储于内存中
.passwordEncoder(passwordEncoder())//解决方案
.withUser("z2zz").password("123456").roles("ADMIN");
}
private PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
Encoded password does not look like BCrypt解决方法:
报错原因:顾名思义设置密码的时候没有进行加密结果导致比对不上
解决方法:在设置密码的时候使用BCryptPasswordEncoder()
加密就行了
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication() // 认证信息存储于内存中
.passwordEncoder(passwordEncoder()).withUser("z2zz")
.password(passwordEncoder().encode(("123456"))).roles("ADMIN");
}
private PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
sec:authorize和sec:authentication属性不起作用
原因:springsecurity和springboot版本不匹配
解决:修改maven依赖,导入springsecurity5
Spring Security 的基本组件 SecurityContextHolder
作用是保留系统当前的安全上下文细节,其中就包括当前使用系统的用户的信息。因此可用于获取当前用户信息
详情参考Spring Security 的基本组件 SecurityContextHolder_Details Inside Spring-CSDN博客_securitycontextholder
REST(Representational State Transfer,表述性状态转移)
REST并非标准而是一种开发Web应用的架构风格,可以将其理解为一种设计模式。
REST Web服务是松耦合的,这特别适用于为客户创建在互联网传播的轻量级的Web服务API。
REST应用是围绕"资源表述的转移"为中心来做请求和响应。数据和功能均视为资源,并使用统一资源标识符(URI)来访问资源。
REST Web服务遵循一些基本的设计原则
1.通过URI来标识资源
系统中的每一个对象或资源都可以通过一个唯一的URI寻址,URI的结构应该简单可预测且易于理解
2.统一接口
CRUD操作与HTTP方法之间的一对一映射
- 若要在服务器上创建资源,应使用POST方法
- 若要检索某资源,应使用GET方法
- 若要更新或添加资源,应使用PUT方法
- 若要删除某个资源,应使用DELETE方法
3.资源多重表述
URI所访问的每个资源都可以使用不同形式加以表示(如XML或JSON),具体的表现形式取决于访问资源的客户端,客户端与服务提供者使用一种内容协商的机制来选择合适的数据格式最小化彼此之间的数据耦合
4.无状态
对服务器端的请求应该是无状态的,完整 独立的请求不要求服务器在处理请求时检索任何类型的应用程序上下文或状态。无状态约束使服务器的变化对客户端是不可见的,因为在两次连续的请求中,客户端并不依赖于同一台服务器。
@RequestParam
用于传递参数
value:参数名字,即入参的请求参数名字,如username表示请求的参数区中的名字为username的参数的值将传入;
required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报404错误码;
defaultValue:默认值,表示如果请求中没有同名参数时的默认值,默认值可以是SpEL表达式
@Transactional
该注解主要用于声明事务。其实现原理是通过SpringAOP在注解修饰方法的前后织入事务管理的实现语句,所以开发者只需要通过一个注解就能代替一系列繁琐的事务开始,事务关闭等重复性的编码任务。编码方式确实简单了,但也因为隐藏了直观的实现逻辑,一些错误的编码方法可能会让@Transactional
注解失效,达不到事务的作用。最直接的表现就是:方法执行过程中抛出了异常,但事务没有回滚,最终导致了脏数据的产生。
1.在同一个类中调用。
public class A {
public void methodA() {
methodB();
// 其他操作
}
@Transactional
public void methodB() {
// 写数据库操作
}
}
这类错误适用于所有基于SpringAOP实现的注解。解决方法:合理规划好层次关系,将methodB方法写到别的类中即可
2.@Transactional修饰的方法不是public
3.不同的数据源
public class TransactionalMistake {
@Transactional
public void createOrder(Order order) {
orderRepo1.save(order);
orderRepo2.save(order);
}
}
4.回滚异常配置不正确
默认情况下,仅对RuntimeException
和Error
进行回滚。如果不是的它们及它们的子孙异常的话,就不会回滚。
所以,在自定义异常的时候,要做好适当的规划,如果要影响事务回滚,可以定义为RuntimeException
的子类;如果不是RuntimeException
,但也希望触发回滚,那么可以使用rollbackFor
属性来指定要回滚的异常。
5.数据库引擎不支持事务
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
这里的spring.jpa.database-platform
配置主要用来设置hibernate使用的方言。这里特地采用了MySQL5InnoDBDialect,主要为了保障在使用Spring Data JPA时候,Hibernate自动创建表的时候使用InnoDB存储引擎,不然就会以默认存储引擎MyISAM来建表,而MyISAM存储引擎是没有事务的。
@ManyToMany注解多对多关系详解:
JPA实体关系映射:@ManyToMany多对多关系、@OneToMany@ManyToOne一对多多对一关系和@OneToOne的深度实例解析。 - 简书
参数cascade:
- CascadeType.PERSIST
官方文档的说明:Cascade persist operation
看到网上很多博客对这一枚举值的解释是:级联持久化(保存)操作(持久保存拥有方实体时,也会持久保存该实体的所有相关数据。)
经过实践检验,我的理解是:给当前设置的实体操作另一个实体的权限。这个理解可以推广到每一个CascadeType。因此,其余CascadeType枚举值将不再一一详细解释。
public class Student {
@ManyToMany(cascade=CascadeType.PERSIST,fetch=FetchType.LAZY)
private Set<Course> courses = new HashSet<>();
//其他代码略。
}
可以看到,我们在上面的代码中给了Student对Course进行级联保存(cascade=CascadeType.PERSIST)的权限。此时,若Student实体持有的Course实体在数据库中不存在时,保存该Student时,系统将自动在Course实体对应的数据库中保存这条Course数据。而如果没有这个权限,则无法保存该Course数据。
- CascadeType.REMOVE
Cascade remove operation,级联删除操作。
删除当前实体时,与它有映射关系的实体也会跟着被删除。 - CascadeType.MERGE
Cascade merge operation,级联更新(合并)操作。
当Student中的数据改变,会相应地更新Course中的数据。 - CascadeType.DETACH
Cascade detach operation,级联脱管/游离操作。
如果你要删除一个实体,但是它有外键无法删除,你就需要这个级联权限了。它会撤销所有相关的外键关联。 - CascadeType.REFRESH
Cascade refresh operation,级联刷新操作。
假设场景 有一个订单,订单里面关联了许多商品,这个订单可以被很多人操作,那么这个时候A对此订单和关联的商品进行了修改,与此同时,B也进行了相同的操作,但是B先一步比A保存了数据,那么当A保存数据的时候,就需要先刷新订单信息及关联的商品信息后,再将订单及商品保存。 - CascadeType.ALL
Cascade all operations,清晰明确,拥有以上所有级联操作权限。
参数fetch:
如果是fetch=FetchType.EAGER,那么表示取出这条数据时,它关联的数据也同时取出放入内存中
如果是fetch=FetchType.LAZY,那么取出这条数据时,它关联的数据并不取出来,在同一个session中,什么时候要用,就什么时候取(再次访问数据库)。
但是,在session外,就不能再取了。用EAGER时,因为在内存里,所以在session外也可以取。
一般只在一边设Eager,JPA接口默认为一对多为Lazy,多对一为Eager,但是Hibernate反向工程生成Entity时,多对一为Lazy,需要手动改为Eager。
@JoinColumn(name="")//注释本表中指向另一个表的外键。
@JoinTable参数
属性 | 是否必须 | 说明 |
---|---|---|
name | 否 | 指定该连接表的表名 |
JoinColumns | 否 | 该属性值可接受多个@JoinColumn ,用于配置连接表 中外键列的信息,这些外键列参照当前实体对应表 的主键列 |
inverseJoinColumns | 否 | 该属性值可接受多个@JoinColumn ,用于配置连接表 中外键列的信息,这些外键列参照当前实体的关联实体对应表 的主键列 |
targetEntity | 否 | 该属性指定关联实体 的类名。在默认情况下,Hibernate将通过反射来判断关联实体的类名 |
catalog | 否 | 设置将该连接表放入指定的catalog中。如果没有指定该属性,连接表将放入默认的catalog |
schema | 否 | 设置将该连接表放入指定的schema中。如果没有指定该属性,连接表将放入默认的schema |
uniqueConstraints | 否 | 该属性用于为连接表 增加唯一约束 |
indexes | 否 | 该属性值为@Index 注解数组,用于为该连接表定义多个索引 |
将Markdown内容转为html格式
maven添加依赖
<dependency>
<groupId>com.github.rjeschke</groupId>
<artifactId>txtmark</artifactId>
<version>0.13</version>
</dependency>
导入下面这个包
import com.github.rjeschke.txtmark.Processor
htmlContent=Processor.process(content);
//将Markdown内容转化为HTML格式
Sort sort=new Sort(Sort.Direction.DESC,"createTime");报错是由于Springboot版本太新改为 Sort sort=Sort.by(Sort.Direction.DESC,"createTime");即可
有一搭没一搭的写的。挺多报错解决没有整理上挺可惜的。总的来说是写了个blog系统仿造新浪blog之类的,后面会把项目整理出来,以及使用elasticsearch的时候报错解决。elasticsearch的报错解决可太不容易了,可能因为国内用的人不多,百度几乎找不到相同报错情况,找到了用他的解决方案也解决不了,感觉这份经验挺难得的,值得整理一下虽然并不是什么不好解决的问题。