Spring、SpringMVC、Mybaits的相关关系

在写代码之前我们先了解一下这三个框架分别是干什么的?
相信大以前也看过不少这些概念,我这就用大白话来讲,如果之前有了解过可以跳过这一大段,直接看代码!

SpringMVC:它用于web层,相当于controller(等价于传统的servlet和struts的action),用来处理用户请求。举个例子,用户在地址栏输入http://网站域名/login,那么springmvc就会拦截到这个请求,并且调用controller层中相应的方法,(中间可能包含验证用户名和密码的业务逻辑,以及查询数据库操作,但这些都不是springmvc的职责),最终把结果返回给用户,并且返回相应的页面(当然也可以只返回json/xml等格式数据)。springmvc就是做前面和后面过程的活,与用户打交道!!

Spring:太强大了,以至于我无法用一个词或一句话来概括它。但与我们平时开发接触最多的估计就是IOC容器,它可以装载bean(也就是我们java中的类,当然也包括service dao里面的),有了这个机制,我们就不用在每次使用这个类的时候为它初始化,很少看到关键字new。另外spring的aop,事务管理等等都是我们经常用到的。

MyBatis:如果你问我它跟鼎鼎大名的Hibernate有什么区别?我只想说,他更符合我的需求。第一,它能自由控制sql,这会让有数据库经验的人(当然不是说我啦捂脸)编写的代码能搞提升数据库访问的效率。第二,它可以使用xml的方式来组织管理我们的sql,因为一般程序出错很多情况下是sql出错,别人接手代码后能快速找到出错地方,甚至可以优化原来写的sql。

本系统用到的最主要的框架就是SSM框架,即由Spring+Spring MVC+MyBaits组成。 Spring是位于底层的框架,Spring MVC框架就是基于Spring框架,并且Spring起到的主要作用就是连接Spring MVC和MyBaits的作用,因为在这个框架中的数据库层主要由持久层来管理的,所以业务层直接调用的是持久层,这要就实现了持久层和业务层的耦合。而且Spring也具有控制反转的作用,当一个对象依赖的类需要注册就交给Spring来控制,所以它的优势也集中体现在AOP(切面编程),通过分离业务与系统级别的服务来达到内聚性的开发。
好了,前面bb那么多,下面我们真正开始敲代码了~
首先我们打开IED,我这里用的是eclipse(你们应该也是用的这个,对吗?),创建一个动态web项目,建立好相应的目录结构(重点!)

① Master以及主服务器的操作记录到二进制日志当中(Binary Log),在每个数据更新之前,Master在日志里记录这些改变,MySql将事务串行地写入二进制当中,在事务写入二进制完成之后,Master通知存储引擎,提交事务。
② 将Master的Binary Log拷回终机日志当中,首先Slave开启一个工作线程,即I/O thread,I/O thread在Master上打开一个互通的连接,然后做Binary Log的处理,I/O thread将日志写入Relay Log内。
③ Slave重做终机日志事件,将改变反映它自己的数据。

③ Layouts:将日志记录的内容从一种数据形式转换成第二种。
在本系统使用Logback日志组件的目的是为了作故障的定位和显示程序运行
的状态。

然后再来讲讲redis,按照五点把书中的内容进行一下整理:

1、为什么要选择Redis:介绍Redis的使用场景与使用Redis的原因;

2、Redis常用命令总结:包括时间复杂度总结与具体数据类型在Redis内部使用的数据结构;

3、Redis的高级功能:包括持久化、复制、哨兵、集群介绍;

4、理解Redis:理解内存、阻塞,这部分是非常重要的,前面介绍的都可以成为术,这里应该属于道的部分;

5、开发技巧:主要是一些开发实战的总结,包括缓存设计与常见坑点。

先来开启第一部分的内容,对Redis来一次重新打量。

Redis不是万金油

在面试的时候,常被问比较下Redis与Memcache的优缺点,个人觉得这二者并不适合一起比较,一个是非关系型数据库不仅可以做缓存还能干其他事情,一个是仅用做缓存。常常让我们对这二者进行比较,主要也是由于Redis最广泛的应用场景就是Cache,那么Redis到底能干什么?又不能干什么呢?

Redis是高性能的内存分布式缓存服务器,通过缓存数据的查询结果来减少数据库访问技术,以提高动态Web应用的速度,提高可扩展性。
Redis是一个key value的存储系统,它支持的存储value类型相对较多,包括字符串、链表、集合、有序集合等。使用Redis操作不用考虑多线程的并发问题,由于此操作是原子性的,不可拆分。在此基础上,Redis支持各种方式的排序,为了保证效率,数据都是缓存在内存中的,区别是Redis会把数据周期性地写入磁盘,或者把修改操作写入追加的记录文件,前者为默认的RDD存储方式,保证了Redis的高效性能,缺点是它有一段时间进行持久化,如果进行持久化的时候,Redis发生故障会导致数据的丢失,所以这种方式更适合对数据要求不严谨的时候,在本系统中我们使用RDD就可以满足要求了。

package com.soecode.lyf.web;

import java.util.List;

import org.apache.ibatis.annotations.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.soecode.lyf.dto.AppointExecution;
import com.soecode.lyf.dto.Result;
import com.soecode.lyf.entity.Book;
import com.soecode.lyf.enums.AppointStateEnum;
import com.soecode.lyf.exception.NoNumberException;
import com.soecode.lyf.exception.RepeatAppointException;
import com.soecode.lyf.service.BookService;

@Controller
@RequestMapping("/book") // url:/模块/资源/{id}/细分 /seckill/list
public class BookController {

private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private BookService bookService;
@RequestMapping(value = "/list", method = RequestMethod.GET)
private String list(Model model) {
List<Book> list = bookService.getList();
model.addAttribute("list", list);
// list.jsp + model = ModelAndView
return "list";// WEB-INF/jsp/"list".jsp
}
@RequestMapping(value = "/{bookId}/detail", method = RequestMethod.GET)
private String detail(@PathVariable("bookId") Long bookId, Model model) {
if (bookId == null) {
return "redirect:/book/list";
}
Book book = bookService.getById(bookId);
if (book == null) {
return "forward:/book/list";
}
model.addAttribute("book", book);
return "detail";
}
//ajax json
@RequestMapping(value = "/{bookId}/appoint", method = RequestMethod.POST, produces = {
"application/json; charset=utf-8" })
@ResponseBody
private Result<AppointExecution> appoint(@PathVariable("bookId") Long bookId, @RequestParam("studentId") Long studentId) {
if (studentId == null || studentId.equals("")) {
return new Result<>(false, "学号不能为空");
}
//AppointExecution execution = bookService.appoint(bookId, studentId);//错误写法,不能统一返回,要处理异常(失败)情况
AppointExecution execution = null;
try {
execution = bookService.appoint(bookId, studentId);
} catch (NoNumberException e1) {
execution = new AppointExecution(bookId, AppointStateEnum.NO_NUMBER);
} catch (RepeatAppointException e2) {
execution = new AppointExecution(bookId, AppointStateEnum.REPEAT_APPOINT);
} catch (Exception e) {
execution = new AppointExecution(bookId, AppointStateEnum.INNER_ERROR);
}
return new Result<AppointExecution>(true, execution);
}

}

因为我比较懒,所以我们就不测试controller了,好讨厌写前端,呜呜呜~

    到此,我们的SSM框架整合配置,与应用实例部分已经结束了,我把所有源码和jar包一起打包放在了我的GitHub上,需要的可以去下载,喜欢就给个star吧,这篇东西写了两个晚上也不容易啊。
修改预约业务代码,失败时抛异常,成功时才返回结果,控制层根据捕获的异常返回相应信息给客户端,而不是业务层直接返回错误结果。上面的代码已经作了修改,而且错误示范也注释保留着,之前误人子弟了,还好有位网友前几天提出质疑,我也及时做了修改。
SET FOREIGN_KEY_CHECKS=0;

-- Table structure for adminuser


DROP TABLE IF EXISTS adminuser;
CREATE TABLE adminuser (
id int(11) NOT NULL AUTO_INCREMENT,
username varchar(255) DEFAULT NULL,
password varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用户登录</title>
</head>
<body>
<form action="<%=request.getContextPath() %>/login.do" method="post">
用户名:<input type="text" name="username" >
密码:<input type="password" name="password" >
<input type="submit" value="登录">
</form>
</body>
</html>

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>修改数据</title>
</head>
<body>
<form action="<%=request.getContextPath() %>/update.do" method="post">
用户名:<input type="text" name="username" value="${add.username}">
密码:<input type="password" name="password" value="${add.password}">
<input type="hidden" name="id" value="${add.id }">
<input type="submit" value="提交数据">
</form>
</body>
</html>