10-MyBatis笔记

MyBatis

day01

Spring MVC 的异常处理

1 普通的异常处理方式有什么不足

普通的异常处理方式可以是try … catch … finally,或者throw + throws。

在一个项目中,可能有些异常出现的频率高较,而频繁的在代码中使用以上处理异常的语法可能比较繁琐。

2 使用SimpleMappingExceptionResolver

通过使用SimpleMappingExceptionResolver,可以配置异常与某些页面的映射关系,配置完成后,无论是处理哪个请求时出现了指定的异常,都会直接到指定的页面!

SimpleMappingExceptionResolver是Spring MVC中已经存在的类,我们需要做的就是在Spring MVC的配置文件中通过<bean>节点配置它,并且在其中配置异常与页面的映射关系即可,例如:

<!-- 配置处理异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
	<property name="exceptionMappings">
		<props>
			<prop key="java.lang.NullPointerException">error1</prop>
			<prop key="java.lang.ArrayIndexOutOfBoundsException">error2</prop>
		</props>
	</property>
</bean>

这种做法比较简单,但是处理得相对比较粗糙,提示的信息不够精准!

3 使用@ExceptionHandler

Controller中,可以自定义方法,使用@ExceptionHandler进行注解,一旦处理请求过程中出现异常,Spring MVC就会自动调用该方法。

自定义的方法和平时使用的处理请求的方法一样,方法名称可以自定义,参数可以根据需要自行添加,通常,至少添加Exception作为参数,以判断异常的类型。

@ExceptionHandler
public String handleException(HttpServletRequest request, 
	Exception ex) {
	request.setAttribute("errorMessage", ex.getMessage());
	
	if (ex instanceof NullPointerException) {
		return "error3";
	} else if (ex instanceof ArrayIndexOutOfBoundsException) {
		return "error4";
	} else {
		return "error5";
	}
}

这种做法也很简单,由于是在程序中进行处理,所以,自由度更高!

这种做法与使用SimpleMappingExceptionResolver是冲突的,在使用这种做法之前,先确保没有使用SimpleMappingExceptionResolver,不要同时使用这2种方式处理相同的异常。

在使用这种做法时,如果需要多个Controller都应用这种处理异常的方式,可以把以上代码写一个父类中,然后每个Controller都继承自这个类!

public abstract class ExceptionController {
	
	@ExceptionHandler
	public String handleException() { .... }

}

public class MainController extends ExceptionController {
	// 这个类用于处理各种请求
}

MyBatis

1 基本概念

MyBatis是在项目中用于解决数据存储的框架,即访问数据库的框架。

使用了MyBatis后,在访问数据库时,只需要定义接口,并配置接口中的抽象方法对应的SQL语句即可,而不需要开发接口的实现类!

2 基本使用

2.1 添加依赖

创建新项目:10-MyBatis-01-Sample,执行常规操作,并添加以下依赖:

Group ID				Artifact				Version
org.springframework		spring-webmvc			3.2.8.RELEASE
commons-dbcp			commons-dbcp			1.4
mysql					mysql-connector-java	5.1.37
junit					junit					4.12
org.springframework		spring-jdbc				3.2.8.RELEASE
mybatis					mybatis					3.2.8
org.mybatis				mybatis-spring			1.3.1

操作完成后,检查在src\main\resources下是否存在数据库连接池的.properties配置文件、文件内是否正确配置,检查Spring的配置文件中是否加载了这个配置、是否配置了BasicDataSource

2.2 设定目标

tedu_ums数据库的t_user数据表中添加1条用户数据,数据中包括username、password、phone、email。

2.3 【开发】创建持久层Java代码

创建cn.tedu.ssm.bean.User实体类,声明id和以上4个属性。

创建cn.tedu.ssm.mapper.UserMapper接口,在接口中声明:

void createUser(User user);

2.4 【开发】创建持久层的映射

先从FTP服务器下载mapper.zip并解压缩。

src\main\resources中新建mappers文件夹,然后粘贴解压缩得到的文件,并重命名为UserMapper.xml

UserMapper.xml的根节点<mapper>中,添加namespace属性,值为匹配的Java接口文件的全名:

<mapper namespace="cn.tedu.ssm.mapper.UserMapper">
</mapper>

然后,在<mapper>中添加子级节点,以对应Java接口中的抽象方法,如果该方法执行的是增加数据操作,则添加<insert>节点,同理,如果执行的是删除操作,则添加<delete>节点,以此类推。此次显然使用<insert>节点,必须配置的属性是id,值为抽象方法的名称,即:

<mapper namespace="cn.tedu.ssm.mapper.UserMapper">

	<!-- 通过子节点配置与抽象方法的映射关系 -->
	<insert id="createUser">
	</insert>

</mapper>

由于对应的方法是有参数的,则在<insert>节点上配置parameterType属性以确定参数的类型,取值为该类型的全名。

然后,在<insert>节点内部,编写此次操作需要执行的SQL语句,在SQL语句中,变量使用#{}表达式,如果SQL语句中变量是方法的参数的某个属性,可以直接写属性名,例如:

<mapper namespace="cn.tedu.ssm.mapper.UserMapper">

	<!-- 通过子节点配置与抽象方法的映射关系 -->
	<insert id="createUser" 
		parameterType="cn.tedu.ssm.bean.User">
		INSERT INTO t_user (
			username, password, 
			phone, email
		) VALUES (
			#{username}, #{password}, 
			#{phone}, #{email}
		)
	</insert>

</mapper>

2.5 【开发】配置MyBatis

在Spring的配置文件中,配置:

<!-- 配置MapperScannerConfigurer -->
<bean  class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<!-- 用于配置持久层接口在哪里 -->
	<property name="basePackage" value="cn.tedu.ssm.mapper" />
</bean>
	
<!-- 配置SqlSessionFactoryBean -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
	<!-- 用于配置数据库连接池 -->
	<property name="dataSource" ref="dataSource" />
	<!-- 用于配置持久层映射文件在哪里 -->
	<property name="mapperLocations"
		value="classpath:mappers/UserMapper.xml" />
</bean>

2.6 【开发】获取新增加的数据的ID

如果需要获取新记录的ID,则在<insert>节点中需要添加2个属性:useGeneratedKeys="true"keyProperty="id",例如:

<insert id="createUser" 
	parameterType="cn.tedu.ssm.bean.User"
	useGeneratedKeys="true"
	keyProperty="id">

当添加这些配置以后,在MyBatis执行增加操作后,会把新记录的ID封装到用于增加操作的对象中,即:如果调用createUser()方法时,使用的User userA对象作为参数,则执行完后,userA中就有了新记录的ID:

userMapper.createUser(user);
Integer id = user.getId();

2.7 小结:如何使用Spring整合后的MyBatis

  1. 添加依赖,依赖的jar包的版本不限,但可以统一版本号的请尽量统一,特别是以spring-作为前缀的!

  2. 配置spring-mvc.xml,在这个文件中,至少要配置:组件扫描、ViewResolver、读取db.properties、配置dbcp(BasicDataSource)、配置MapperScannerConfigurer、配置SqlSessionFactoryBean,如果这些配置是从其它的项目中复制过来的,请检查值是否需要修改!

  3. 编写接口文件,并定义抽象方法,如果需要相关实体类,则创建所需的实体类

  4. 配置对应的映射:Mapper.xml文件可以从FTP下载,或从此前的项目中复制,通常推荐将这个文件存放在src\main\resources\mappers下(请与Spring配置中保持一致),然后编辑文件的内容

3 练习:查询特定的某条数据

3.1 设定目标

在以上基础之上,添加根据用户名查询数据的功能。

3.2 【开发】持久层–接口

UserMapper.java接口中添加新的抽象方法:

User findUserByUsername(String username);

3.3 【开发】持久层–映射

UserMapper.xml映射文件中添加<select>子节点:

<select id="findUserByUsername"
	resultType="cn.tedu.ssm.bean.User">
	SELECT 
		id, username, password, phone, email  
	FROM 
		t_user 
	WHERE 
		username=#{username}
</select>

在配置这些节点时,如果接口中声明的方法只有1个参数,并且是基本数据类型或String类型,可以不需要通过parameterType指定参数的数据类型。

由于此次操作是需要返回值的,则需要在<select>节点添加resultType属性指定返回值的数据类型。

3.4 【测试】

在测试类中进行测试。

4 练习:查询多条数据

4.1 设定目标

查询所有用户数据,不指定查询条件

4.2 【开发】持久层–接口

UserMapper.java接口中添加新的抽象方法:

List<User> findAllUser();

4.3 【开发】持久层–映射

UserMapper.xml映射文件中添加<select>子节点:

<select id="findAllUser"
	resultType="cn.tedu.ssm.bean.User">
	SELECT 
		id, username, password, phone, email  
	FROM 
		t_user
</select>

4.4 【测试】

在测试类中进行测试。

5 练习:删除数据

5.1 设定目标

根据ID删除数据

5.2 【开发】持久层–接口

UserMapper.java接口中添加新的抽象方法:

Integer delete(Integer id);

5.3 【开发】持久层–映射

UserMapper.xml映射文件中添加<delete>子节点:

<delete id="delete">
	DELETE FROM 
	t_user 
	WHERE 
	id=#{id}
</delete>

5.4 【测试】

在测试类中进行测试。

6 练习:修改数据

6.1 设定目标

根据id修改密码、手机号码、电子邮件,不允许修改用户名。

6.2 【开发】持久层–接口

UserMapper.java接口中添加新的抽象方法:

Integer updateUserInfo(User user);

6.3 【开发】持久层–映射

UserMapper.xml映射文件中添加<update>子节点:

<update id="updateUserInfo"
	parameterType="cn.tedu.ssm.bean.User">
	UPDATE 
		t_user 
	SET 
		password=#{password},phone=#{phone},email=#{email} 
	WHERE 
		id=#{id}
</update>

6.4 【测试】

在测试类中进行测试。

day02

关于修改数据时的问题

1 问题

通过MyBatis实现修改数据,配置的映射是:

<update id="updateUserInfo"
	parameterType="cn.tedu.ssm.bean.User">
	UPDATE 
		t_user 
	SET 
		password	=	#{password},
		phone		=	#{phone},
		email		=	#{email} 
	WHERE 
		id=#{id}
</update>

所以,如果调用该功能时,假设参数中并没有封装phone的数据,则默认为null,最终数据表中该记录的phone字段将被赋null值。

2 解决目标

如果调用该功能时,没有提供新的phone的数据,则不修改原有的phone数据,对于password、email的数据也是同样处理!

/**
 * 修改用户数据,不支持修改用户名
 * @param user 必须封装被修改的用户的ID,
 * 	不需要封装用户名,
 * 	对于phone、email、password的字段,
 * 	如果需要修改,则封装新的值,
 * 	如果不需要修改,则无须封装值
 * @return 如果修改完成,则返回1,
 * 	如果需要修改的数据不存在,则返回0。
 */
Integer updateUserInfo(User user);

3 实现思路

先通过ID查询被修改的用户数据,在执行修改之前,对新数据进行判断,如果某些字段为null值,则使用从数据表中查询到的数据封装进去即可。

即:假设修改id=1的数据,先查询这条数据,以手机号为例,假设从数据表中查询到的手机号是13900139001,如果修改时,使用的User对象中没有封装手机号码,则使用则查询到的手机号码封装到User对象中,最终在执行修改时,User对象中会包含与数据表中一致的手机号码,则可以实现设计目标。

4 实现步骤

4.1 在持久层实现根据ID查询数据的功能

UserMapper.java接口中添加新的抽象方法:

User findUserById(Integer id);

UserMapper.xml中配置映射。

4.2 创建业务层接口

创建cn.tedu.ssm.service.IUserService接口,添加所有持久层已经实现的方法:

4.3 创建业务层实现类

创建cn.tedu.ssm.service.UserServiceImpl类,实现以上业务层接口,在类中声明private UserMapper userMapper;并使用@Resource进行注解,还需使用@Serivce("userService")对类进行注解,实现过程中,直接调用持久层来完成,暂时不编写业务逻辑。

4.4 测试

使用单元测试

MyBatis 动态SQL

1基本概念

在使用MyBatis时,配置映射文件(.xml)时,使用的SQL语句可以添加一些语句,从而使得最终的SQL语句是可变的!

2 基本使用

在编写映射中的SQL语句时,例如可以添加进行判断,使得SQL语句中的其中一部分会根据判断条件来决定是否需要。例如:

<update id="update"
	parameterType="cn.tedu.ssm.bean.User">
	UPDATE 
		t_user 
	SET 
		password	=	#{password},
		<if test="phone != null">
		phone		=	#{phone},
		</if>
		email		=	#{email} 
	WHERE 
		id=#{id}
</update>

3 练习if的使用

3.1 设定目标

在项目中,需要实现:“修改密码”、“修改手机号码”、“修改电子邮箱”这3个功能

3.2 分析

在映射文件中,使用<if>即可判断到底执行哪个字段的更新操作。

3.3 实现功能

  1. UserMapper.java接口中声明名称较为泛化的方法:

    Integer update(User user);

  2. 配置UserMapper.xml映射:

    UPDATE t_user SET password = #{password} phone = #{phone} email = #{email} WHERE id=#{id}
  3. 单元测试,测试时需要注意:在User对象,只封装password、phone、email中的某1项,而不要同时封装多项!

  4. 在业务逻辑层IUserService接口中声明抽象方法:

    Integer updatePassword(Integer id, String password);

    Integer updatePhone(Integer id, String phone);

    Integer updateEmail(Integer id, String email);

  5. 在业务逻辑层UserServiceImpl实现类中实现以上方法

  6. 单元测试

4 什么时候需要使用动态SQL

如果使用了动态SQL,可以根据参数的值的不同,使得最终执行的SQL语句不同。

使用动态SQL可以使得同一个方法可以实现多种不同的目标,例如以上update()方法最终可以演变为updatePassword()updatePhone()等方法。

所以,动态SQL是对SQL语句无法编程的一种补充。

但是,动态SQL只是为了便于利用SQL语句,并不是为了解决业务中存在的问题的!

AJAX

1 基本概念

AJAX用于向服务器发出异步请求,并获取结果的技术。

使用AJAX的本质还是在使用JavaScript编程。

可以想像为:AJAX就是一个看不到的浏览器,用于向服务器发出请求,并获取响应结果!

当AJAX请求获取响应结果后,可以结合JavaScript实现对网页的某个部分的显示效果进行更新,俗称“局部刷新”。

使用AJAX相对于传统的请求方式而言,无论是用户体验还是访问效率都会高许多!

使用AJAX必须在原有的页面的基础之上才可以!

2 练习

2.1 设计目标

设计login.html页面,用于模拟登录,在这个页面中添加1个<form>,其中包含2个<input type="text" />分别用于输入用户名和密码,还包含1个<input type="button" />按钮。

当点击按钮后,将提交POST类型的请求,提交到http://SERVER:PORT/PROJECT/handle_login.do中,假设正确的用户名是ajax,匹配的密码是ajax888,如果提交的数据是正确的,则响应1,如果提交的数据无法登录,则响应0

最终,如果得到的登录结果是1,使用alert()函数提示登录成功!否则,在输入用户名的输入框下显示登录失败的字样。

2.2 开发

2.2.1 创建项目

创建项目11-AJAX-DAY01-Login,生成web.xml,添加Tomcat Runtime,添加依赖:spring-webmvc,复制spring-mvc.xml文件并检查文件内容,配置web.xml

2.2.2 显示登录页面

设计登录页面的访问路径:http://SERVER:PORT/PROJECT/login.do

开发实际显示的页面:WEB-INF/login.jsp,页面中至少包括以上设计的标签。

创建cn.tedu.ajax.controller.UserController类,使用@Controller注解,并添加方法以处理请求,处理的方式是直接转发:

@RequestMapping("/login.do")
public String showLogin() {
	return "login";
}

2.2.3 测试访问页面

在浏览器输入网址,需要能够正确的显示登录页面。

2.2.4 服务器端响应

在服务器端的UserController中添加处理“登录”请求的方法,在完成测试之前先使用GET方法的请求:

@RequestMapping(method=RequestMethod.GET, 
	value="/handle_login.do")
public String handleLogin() {
}

需要接收用户提交的用户名和密码,所以,需要在方法中添加2个参数:

public String handleLogin(String username, String password) {
}

然后,在方法中对用户名和密码进行判断:

if ("ajax".equals(username) && "ajax888".equals(password)) {
	// 登录成功,响应"1"
} else {
	// 登录失败,响应"0"
}

如果需要响应的是一个字符串,而不是响应某个View组件,在处理请求的方法之前添加@ResponseBody注解即可!

@RequestMapping(method=RequestMethod.GET, 
	value="/handle_login.do")
@ResponseBody
public String handleLogin(String username, String password) {
	if ("ajax".equals(username) && "ajax888".equals(password)) {
		// 登录成功,响应"1"
		return "1";
	} else {
		// 登录失败,响应"0"
		return "0";
	}
}

并且,在spring-mvc.xml中,在根节点下添加:<mvc:annotation-driven />

2.2.5 测试提交后的登录处理

在浏览器输入网址例如:http://http://localhost:8080/11-AJAX-DAY01-Login/handle_login.do?username=ajax&password=ajax888

测试完成后,可将处理请求的请求类型调整为POST

2.2.6 发出AJAX请求

为了便于使用,先创建一个函数,专门用于获取XMLHttpRequest对象:

<script type="text/javascript" language="javascript">
	function getXMLHttpRequest() {
		var xhr;
		if (window.XMLHttpRequest) {
			xhr = new XMLHttpRequest();
		} else {
			xhr = new ActiveXObject("Microsoft.XMLHttp");
		}
		return xhr;
	}
</script>

然后,在登录界面中为2个输入框都设置id属性:

<input id="username" type="text" name="username" />
<input id="password" type="text" name="password" />

然后,再编写发出请求的函数,以备调用:

function handleLogin() {
	var xhr = getXMLHttpRequest();
	var u = document.getElementById("username").value;
	var p = document.getElementById("password").value;
	var url = "handle_login.do?username=" + u + "&password=" + p;
	xhr.onreadystatechange = funtion() {
		if (xhr.readyState == 4 && xhr.status == 200) {
			alert(xhr.responseText);
		} 
		//else {
		//	alert("出错啦!!!");
		//}
	};
	xhr.open("GET", url, true);
	xhr.send();
}

在“登录”中配置onclick="handleLogin()"

AJAX的使用方式

核心对象

在AJAX中,使用XMLHttpRequest对象发出请求,并获取响应结果。获取对象的方式与Java中相同:

var xhr = new XMLHttpRequest();

以上语法适用于主流浏览器,包括:Chrome、FireFox、Safari、IE 8+,对于低版本的IE浏览器,需要:

var xhr = new ActiveXObject("Microsoft.XMLHttp");

为了保证兼容低版本的IE,应该:

var xhr;
if (window.XMLHttpRequest) {
	xhr = new XMLHttpRequest();
} else {
	xhr = new ActiveXObject("Microsoft.XMLHttp");
}

核心对象的使用

如果需要发出请求,必须先调用XMLHttpRequest对象的open(method, url, isAsync)函数,然后调用send()函数。

如果需要处理结果,还需要配置XMLHttpRequest对象的onreadystatechange属性,它的值是另一个处理函数,即需要另编写一个函数决定如何处理响应结果。

所以,正确的使用方式:先配置onreadystatechange属性,然后调用open()函数,最后调用send()函数!

核心对象的属性

a) onreadystatechange:值是处理响应结果的函数

b) readyState:准备状态,其值是数值,共5个,分别是:0-尚未初始化、1-与服务器已经建立连接、2-已发出请求、3-请求已接收,并正在处理、4-已响应

c) status:响应码,例如200、404

d) responseText:服务器响应的正文

e) responseXML:服务器响应的XML

发布了15 篇原创文章 · 获赞 0 · 访问量 225

猜你喜欢

转载自blog.csdn.net/weixin_44847293/article/details/105239084