1.1)下载后,解压并导入IDEA中,再添加其他需要的依赖。
1.2)springboot与其他组件的整合非常方便,只需要在src/main/resources目录下的application.properties文件中添加相应配置即可。
1.3)我们先新建几个常用的包domain、dao、service、controller...
2.1)首先在resources/templates目录下新建一个hello.html文件
hello
2.2)然后在controller目录下新建一个DemoController.java文件
@Controller
public class DemoController {
@GetMapping("/thymeleaf")
public String thymeleaf(Model model){
model.addAttribute("name", "wyq");
return "hello";
}
}
然而启动时出现问题,百度后,通过降低springboot版本,才解决,之前使用的是2.1.2,改为1.5.9版本。
再次启动:
2.3)打开浏览器,访问8080端口下的/thymeleaf.html(要添加.html的后缀,这是在配置文件中自己配置的)
显示了我们之前添加的内容,表明springboot整合thymeleaf成功。
2.4)另外说一点:作为一个controller,它里面的方法总共分为两大类:一类是rest api json输出;另一类是页面。
json输出时,一般来说,我们的客户端和服务端会做一个接口的约定,例如,我们的输出结果是一个json结构,里面有这么几个属性:code代表错误码,msg代表错误信息,data代表成功时的数据。
{
"code":XXX
"msg":XXX
"data":XXX
}
那么,做这样的封装有什么好处呢?假如我们约定0代表成功,那么客户端只要得到code是0,就可以从data中取数据;假如我们约定500100表示session失效,那么客户端只要看到500100,就可以直接跳转到登陆页面。所以说,这种方式,无论是对客户端还是对服务端来说,都是非常方便的。
那么,我们就先对接口的输出结果做一个类似的封装
public class Result {
private int code;
private String msg;
/**
* 因为不知道data具体是哪种类型,所以写成泛型
*/
private T data;
...
但是,这样在写代码时还是有点儿问题,在controller中,有一个方法,就需要new Result(XXX,XXX,XXX)
@GetMapping("/hello")
@ResponseBody
public Result hello(){
return new Result(0, "success", "hello wyq!");
}
@GetMapping("/helloError")
@ResponseBody
public Result helloError(){
return new Result(500102, "XXX");
}
...
这样显然不合适,controller不止一个,controller中的方法也不止一个,这样要写太多的new Result(XXX,XXX,XXX)。
那么,我们可不可以用一个常量类来解决这问题?把他们都写到常量类中可不可以?当然可以,但是还是有问题:因为我们这里的code和msg是一对,所以说,最好的办法,就是把他们都放在一块。
我们想要实现什么效果呢?成功时Result.success(data);失败时Result.error(CodeMsg xxx);CodeMsg是个对象,封装了code和msg的对应信息。可以将所有的CodeMsg都写在这个类中,后期维护也很方便。
public class CodeMsg {
private int code;
private String msg;
......
那么,我们来修改一下这个Result类,添加几个方法
/**
* 这里改为private,因为我们不希望用户通过构造函数来生成Result对象
* 而是通过我们封装好的方法来生成对象
* @param data
*/
private Result(T data) {
this.code = 0;
this.msg = "success";
this.data = data;
}
public Result(CodeMsg cm) {
if(cm == null) {
return;
}
this.code = cm.getCode();
this.msg = cm.getMsg();
}
/**
* 成功时调用
* @param data
* @param
* @return
*/
public static Result success(T data) {
return new Result(data);
}
/**
* 失败时调用
* @param cm
* @param
* @return
*/
public static Result error(CodeMsg cm) {
return new Result(cm);
}
到此为止,封装完成。我们再来测试一下:
@GetMapping("/hello")
@ResponseBody
public Result hello(){
//成功时只需要传递数据
return Result.success("hello wyq!");
//return new Result(0, "success", "hello wyq!");
}
@GetMapping("/helloError")
@ResponseBody
public Result helloError(){
//失败时只需要传递CodeMsg
return Result.error(CodeMsg.SERVER_ERROR);
//return new Result(500102, "XXX");
}
效果(由于没写对应的页面,所以访问时不添加后缀.html):
好了,rest api json输出就说这么多,我们来看一下controller中的另一类方法:页面。
这里就是集成thymeleaf做页面模板,上面的hello:wyq的例子就是,这里就不多说了。
3.1)新建实体类User
public class User {
private int id;
private String name;
...
3.2)新建对应的UserDao接口
@Mapper
public interface UserDao {
/**
* 通过@Param定义参数id,然后再使用#{} 来引用这个参数
* @param id
* @return
*/
@Select("select * from user where id = #{id}")
public User getById(@Param("id") int id);
}
由于比较简单,这里不再做单元测试。
@Service
public class UserService {
@Autowired
UserDao userDao;
public User getById(int id) {
return userDao.getById(id);
}
}
@GetMapping("/db/get")
@ResponseBody
public Result doGet(){
User user = userService.getById(1);
return Result.success(user);
}
3.3)DemoController中添加doGet方法,往数据库中插入一条数据
启动工程,测试:
到这里,其实已经测试成功,mybatis配置完成。
3.4)下面再测试一下事务
插入一条id为2的记录,再插入一条id为1的记录
在UserDao中添加
@Insert("insert into user(id, name) values(#{id}, #{name})")
public int insert(User user);
UserService添加
@Transactional
public boolean tx() {
User u1= new User();
u1.setId(2);
u1.setName("2222");
userDao.insert(u1);
User u2= new User();
u2.setId(1);
u2.setName("11111");
userDao.insert(u2);
return true;
}
同在一个事务中,第二条插入失败,会使第一条插入成功的也回滚。
DemoController中添加
@GetMapping("/db/tx")
@ResponseBody
public Result dbTx(){
userService.tx();
return Result.success(true);
}
测试:
肯定会出错,下面看一下数据库,id为2的记录有没有插入进去
没有插入。
去掉事务注解后再次测试
好的,依然会有错误,查看数据库数据
我们可以看到id为2的数据插入成功!至此,springboot与mybatis的集成完毕!!!
4.1)为什么使用fastjson呢?用来把java对象转化为字符串,存到redis中
因为对象序列化最快,效率最高的就是google的Protobuf,但是google的Protobuf的一个缺点是:它序列化之后是不可读的,是一种二进制格式,但是用fastjson之后,他是一个json格式,明文可读,这样方便我们查看,他们效率差多少呢?大概是差了一倍,如果Protobuf用了1毫秒,则fastjson用2毫秒,为了方便,我们使用fastjson。
4.2)封装redis操作
1)在redis包中新建一个RedisConfig类,用来加载配置文件中有关redis的配置信息:
2)新建一个RedisPoolFactory类,利用RedisConfig的对象,将JedisPool注入到spring容器中:
3)再新建一个RedisService类,利用RedisPool的对象完成对redis的具体操作(这里是自己写对jedis的操作,主要是为了练习,所以没有使用springboot整合的redis)
【以上3个类,就不列出了,后面会给出所有代码。】
4.3)这里还要注意的是,对redis中的key的设计,在原来的key的基础上添加前缀,来更好的区分各种key。
4.4)对redis配置完以后,我们在DemoController中做个测试:
@GetMapping("/redis/get")
@ResponseBody
public Result redisGet(){
User user = redisService.get(UserKey.getById, "" + 1, User.class);
return Result.success(user);
}
@GetMapping("/redis/set")
@ResponseBody
public Result redisSet(){
User user = new User();
user.setId(1);
user.setName("哈哈");
redisService.set(UserKey.getById, ""+ 1, user); //UserKey:id1
return Result.success(true);
}
先启动redis,通过客户端查看其中的值,没有任何key:
再运行程序,调用set方法:
再次查看(这里为了方便,直接用图形化客户端进行查看),redis中有值:
再调用get方法:
到此为止,redis这里基本完成了。