Java中SSM框架全面知识点,业务时间的精神食粮
------------------异常
问题 :出现重复定义了访问路径
java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'userController' bean method
406 请求头和响应头不匹配
做ajax注册的时候 出现的问题
ClassNotFindException说明缺少jar包 或者名字写错
NoSuchBeanDefinitionException
如果BeanFactory在Spring Context中没有找到bean的实例,就会抛出这个常见的异常
或者是配置文件的名字写错
为了防止出现EmptyResultDataAccessException查不到数据 可以在dao层加一个try-catch 增加软件健壮性
Controller在编写的时候一定要写完 不要写一半不然会影响样式的显示
BindException:???绑定异常 jvm 异常 在任务管理器关闭一个jvm
可以把spring的标签库换成原来的jstl的标签库
IncorrectResultSizeDataAccessException:有可能注册没做好 数据库保存了俩个相同的账号 则登录不了
问题: 自己写的Controller都对 gologin.do也都对 但是总是报 noMaopper说明扫描包的时候没有扫描到 看配置文件
----onblur 失去焦点 写sql语句的时候 参数传递一定要按照顺序
oldpassword.on("blur",function(){
$.ajax({
type:"GET",
url:path+"/user/chekOldPwd.json",
data:{method:"pwdmodify",oldpassword:oldpassword.val()},
dataType:"json",
success:function(data){
if(data.result == "true"){//旧密码正确
validateTip(oldpassword.next(),{"color":"green"},imgYes,true);
}else if(data.result == "fasle"){//旧密码输入不正确
validateTip(oldpassword.next(),{"color":"red"},imgNo + " 原密码输入不正确",false);
}else if(data.result == "sessionerror"){//当前用户session过期,请重新登录
validateTip(oldpassword.next(),{"color":"red"},imgNo + " 当前用户session过期,请重新登录",false);
}else if(data.result == "error"){//旧密码输入为空
validateTip(oldpassword.next(),{"color":"red"},imgNo + " 请输入旧密码",false);
}
},
error:function(data){
//请求出错
validateTip(oldpassword.next(),{"color":"red"},imgNo + " 请求错误",false);
}
});
学习Spring+SpringMVC+jdbc开发需要的架包
aopalliance-1.0.jar
aspectjweaver-1.6.9.jar
commons-dbcp-1.4.jar
commons-logging-1.2.jar
commons-pool-1.6.jar
hibernate-validator-4.3.2.Final.jar
jboss-logging-3.1.0.CR2.jar
log4j-1.2.17.jar
mysql.jar
spring-aop-3.2.18.RELEASE.jar
spring-beans-3.2.18.RELEASE.jar
spring-context-3.2.18.RELEASE.jar
spring-core-3.2.18.RELEASE.jar
spring-expression-3.2.18.RELEASE.jar
spring-jdbc-3.2.18.RELEASE.jar
spring-tx-3.2.18.RELEASE.jar
spring-web-3.2.18.RELEASE.jar
spring-webmvc-3.2.18.RELEASE.jar
validation-api-1.0.0.GA.jar
1 什么是框架技术
是一个应用程序的半成品
提供可重用的公共结构
按一定规则组织的一组组件
2 优势
1 不在考虑公共的问题
2 专心在业务实现上
3 结构统一 易于学习 维护
4 新手也可以写出好程序
3 主流框架
(0) struts2 (mvc设计模式的实现,拦截器,可变和可重用的标签)
(0) HIBERNATE (封装了jdbc orm简化数据库操作 Dao层)
(0)EJB3是sun公司的官方框架
重点 (1)Spring
依赖注入容器/aop实现 声明式事务 简化java ee 应用 粘合剂 组织大家在一起
(2) SpringMVC
结构最清晰的mvc Model2实现 高度可配置,支持多种视图技术 定制化开发
(3) mybatis
小巧灵活简单易学 特别适合互联网项目 半自动化的orm实现 dao层 动态sql
4 --Spring核心概念-----( 轻量级 非侵入性(不用继承框架的类)的一站式应用开发框架(平台) )
什么是企业级系统?
大规模: 用户数量多, 数据规模大 , 功能模块众多,
性能和安全性要求高
业务复杂
灵活多变
目标: 实现了一个全方位的整合框架 实现一站式的企业应用开发
4大内容结构: IOC容器 AOP实现 数据访问层的支持 web的集成
理念 : 面向bean编程
俩大核心技术: IOC容器 AOP实现
IOC 控制反转 DI 依赖注入(IoC:Inversion of Control)(DI:Dependency Injection )
AOP 面向切面编程
优点
低侵入式设计 独立于各种应用服务器 依赖注入特性将组件关系透明化,降低了耦合度
面向切面编程特性允许将通用任务进行集中式处理 与第三方框架的良好整合
5 IOC的知识点
将组件对象的控制权从代码本身转移到外部容器
组件化的思想:分离关注点,接口和实现分离
依赖的注入:将组件的构建和使用分开
6 配置spring运行环境
1 先导入11 个Spring的jar包(其实包括ioc需要用的 还有jdbc beans aop需要的)
2 添加数据业务接口和实现类
2 解耦合 添加一个属性 是接口 保留一个set访问器
3 在创建一个源文件里面放置一个xml的配置文件
添加数据访问层的组件 业务逻辑层的组件 列如:
<!-- 数据访问层的一个组件 没有属相的话可以直接去掉结束标签加个/-->
<bean id="userDaoImpl" class="cn.kgc.user.dao.UsrDaoImpl"/>
<!-- 业务逻辑层的组件 -->
<bean id="userService" class="cn.kgc.user.service.UserServiceImpl">
<property name="userDao" ref="userDaoImpl"></property>
</bean>
4 再次创建一个test资源包
代码:通过创建ApplicationContext接口读取resources源文件里面的配置文件 取出来UserService对象从而调用他的方法
public static void main(String[] args) {
//配置文件的路径
String configLocation="applicationContext.xml";
//创建对象 读取配置文件 就有了spring容器组件 相当于创建IOC容器
ApplicationContext context=new ClassPathXmlApplicationContext(configLocation);
//导入源码包
//从容器中取出来需要的组件 UserService.class利用泛型不需要强转了
UserService userService=context.getBean("userService" ,UserService.class);
//最后就可以调用UserService接口的方法了
User user=userService.login(" ", " ");
}
使用过程中注意大小写命名规范
<property name="userDao" ref="userDaoImpl" value="呵呵呵"></property>
name代表的是属性 value代表的是属性值 ref是引用dao层的类
id代表bean的唯一标识 class代表要管理的内容 (包名+类名)
7 配置文件bean的编写规则
8 Spring核心API
BeanFactory
applicationContext
ApplicationContext 是 BeanFactory 的子接口
它的实现类 ClassPathXmlApplicationContext
--------------------4月3号知识点-----------------------IOC控制反转的深入知识点
Spring实现依赖注入的几种方式:1 2 3 4种方式
1《设值注入》 (重点)
带有set访问器的叫做
<bean id="userDaoImpl" class="cn.smbms.dao.user.UserDaoImpl"/>
<!-- 添加业务逻辑层的组件 -->
<bean id="userServiceImpl" class="cn.smbms.service.user.UserServiceImpl">
<property name="userDao" ref="userDaoImpl" value="呵呵呵"></property>
</bean>
2 《构造注入》
如何通过构造注入为业务类注入所依赖的数据访问层对象,实现保存用户数据的功能?
练习 :------------- 类里面有一个带参构造
public UserServiceImpl(UserDao userDao,String userCode){
this.userCode=userCode;
this.userDao=userDao;
System.out.println(userCode);
}
-----------------配置文件中
<!-- 添加数据访问层的组件 -->
<bean id="userDaoImpl" class="cn.smbms.dao.user.UserDaoImpl"/>
<!-- 添加业务逻辑层的组件 -->
<bean id="userServiceImpl" class="cn.smbms.service.user.UserServiceImpl">
<!-- 构造注入 一个consturctor代表一个构造器里面的属性 -->
<constructor-arg ref="userDaoImpl" index="0"></constructor-arg>
<constructor-arg value="张三" index="1"></constructor-arg>
</bean>
<constructor-arg><ref bean="userDao" /></constructor-arg>
一个<constructor-arg>元素表示构造方法的一个参数,且使用时不区分顺序。
通过<constructor-arg>元素的index 属性可以指定该参数的位置索引,位置从0 开始。
<constructor-arg>元素还提供了type 属性用来指定参数的类型,避免字符串和基本数据类型的混淆。
3 p命名空间注入属性值
p:userDao-ref 引用其他类 p:id 基本数据引用其他类型
1:必须先在Spring配置文件中引入P命名空间 类里面必须有set访问器
xmlns:p="http://www.springframework.org/schema/p"
特点:使用属性而不是子元素的形式配置Bean的属性,从而简化了配置代码
代码练习:
类里面的属性private UserDao userDao;
private String userCode;
private Integer id;
配置文件中
<!-- 添加数据访问层的组件 -->
<bean id="userDaoImpl" class="cn.smbms.dao.user.UserDaoImpl" />
<!-- 添加业务逻辑层的组件 -->
<bean id="userServiceImpl" class="cn.smbms.service.user.UserServiceImpl"
p:userDao-ref="userDaoImpl" p:userCode="张三" p:id="6" />
4 注解注入(重点)
注解:描述数据的数据(元注解 自定义注解 內建注解)
注解方式将Bean的定义信息和Bean实现类结合在一起,
Spring提供的注解有
@Component: 实现Bean组件的定义
@Repository :用于标注DAO类
@Service : 用于标注业务类
@Controller :用于标注控制器类
用注解代替<bean>
注意&&&&&
使用@Autowired注解实现Bean的自动装配,默认按类型匹配,
可以使用@Qualifier指定Bean的名称
使用@Resource注解实现组件装配,默认按名称匹配----------------》等同于autowrited自动装配
<!-- 扫描包中注解标注的类 -->
<context:component-scan base-package="service,dao" />
指定需要扫描的基类包,多个包可用逗号隔开
列如 1 dao层的实现类 放一个@Repository(取个名字)--> @Repository("userDao")
2 sevice的实现类 ----》 @Service("userService") 放在类上面
3在业务的属性上加
@Autowired
private UserDao userDao;
4 使用注解bean都可以省略
一定要在配置文件加上命名空间 再加一个扫描包
最后一定*********** 使用注解开启SpringIOC容器
<context:component-scan base-package="cn.smbms.dao.user,cn.smbms.service.user">
</context:component-scan>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
">
5 @Autowired
@Qualifier("userDao")-----------------建议一起使用@Qualifier指定Bean的名称
6 注意如果dao层有俩个实现类注意@Repository(名字不要冲突)
可以使用@Qualifier()指定使用哪一个dao层实现类
5 设值注入 构造注入二者相比的优点和缺点
设值:灵活性好但是set方法数量较多
时效性差 通过无参构造实例化
构造:灵活性差 仅靠重载限制太多
时效性好 通过匹配的构造实例化 建议保留无参构造
6 注入不同的数据类型
1 注入直接量
使用<value>标签实现
注意特殊字符的处理
2 引用Bean
使用<ref>标签实现
注意bean属性和 local 属性的区别
3 使用内部Bean
<property name="dao">
在属性里面引入新的bean
<bean class="dao.impl.UserDaoImpl"/>
</property>
4 注入集合类型的属性
分别使用<list>、<set>、<map>、<props>标签实现
5 注入null 和空字符串值
使用<null/>注入null 值
使用<value></value>注入空字符串值
------代码练习 使用IOC注入不同的属性值
private Integer id;
private String userName;
private List<String> list;
private List<User> userlist;
private Map<String, String> map;
private Map<String, User> usermap;
<!-- 外部类 -->
<bean id="user" class="cn.smbms.pojo.User" p:userName="李四" />
<bean id="testType" class="cn.smbms.pojo.TestType">
<property name="id" value="100"></property>
<property name="userName" value="威哥"></property>
<property name="list">
<list>
<value>测试list的开始</value>
<value>美国</value>
<value>中国</value>
<value>测试list结束</value>
</list>
</property>
<property name="userlist">
<list>
<!-- 内部类 -->
<bean class="cn.smbms.pojo.User" p:userName="张三"></bean>
<bean class="cn.smbms.pojo.User" p:userName="张三"></bean>
<ref bean="user"/>
</list>
</property>
<property name="map">
<map>
<entry>
<key><value>map的测试 头</value></key>
<value>map的开始 尾</value>
</entry>
<entry>
<key><value>US</value></key>
<value>美国</value>
</entry>
<entry>
<key>
<value>CH</value>
</key>
<value>中国</value>
</entry>
</map>
</property>
<property name="usermap">
<map>
<entry>
<key><value>admin1</value></key>
<bean class="cn.smbms.pojo.User" p:userName="杨威"></bean>或者<ref bean="user"/>
</entry>
<entry>
<key> <value>admin2</value></key>
<bean class="cn.smbms.pojo.User" p:userName="刘妮"></bean>
</entry>
</map>
</property>
</bean>
------测试类
public static void main(String[] args) {
ApplicationContext act = new ClassPathXmlApplicationContext(
"applicationContext.xml");
TestType t = act.getBean("testType", TestType.class);
System.out.println(t.getId() + t.getUserName());
for (String string : t.getList()) {
System.out.println(string);
}
for (User user : t.getUserlist()) {
System.out.println(user.getUserName());
}
Map<String, String> map = t.getMap();
for (String key : map.keySet()) {
String value = map.get(key);
System.out.println(key + "===" + value);
}
Map<String, User> map2=t.getUsermap();
for (String key : map2.keySet()) {
User user=map2.get(key);
System.out.println(key);
System.out.println(user.getUserName());
}
}
-----properties集合的注入
<property name=“”>
<props>
<prop key="key1">test prop1</prop>
<prop key="key2">test prop2</prop>
</props>
</property>
--------------------4月4号------------------
1
spring使用的XM解析技术是(JDOM)
SpringIOC底层代码实现的原理 JDOM 反射(50页)
Spring框架使用的设计模式:工厂模式 单例模式 代理模式
大众框架 SSH SSM
小众框架 软件公司架构师自己研发的框架
mybateis配置文件的根元素 --> <configuration>
1 耦合 解耦合 高内聚
(1)两个程序模块有关联就叫做耦合。
(2) 解耦: 并不是字面意义上的把关联拆掉,而是把模块之间的关联放松到必要的程度。一些建议:
模块只对外暴露最小限度的接口,形成最低的依赖关系。
只要对外接口不变,模块内部的修改,就不得影响其他模块;
删除一个模块,应当只影响有依赖关系的其他模块,而不应该影响其他无关部分;
就是把必要的耦合理顺,同时尽量减少不必要的耦合
(3) 高内聚: 是指一个软件模块是由相关性很强的代码组成,只负责一项任务,
也就是常说的单一责任原则。
2 XML解析技术
JDOM DOM DOM4j SAX
3 单列模式 构造私有化 静态方法new 对象 (平常用的是懒汉)
然后单列分为懒汉和饿汉模式
饿汉式在类加载的时候就完成初始化
代码练习:
------------》懒汉式
public class Singletion{
public static Singletion singletion;
private Singletion(){
}
public static Singletion getInstance(){
if(singletion==null){
singletion=new Singletion();
}
}
}
------------》饿汉式
public class Singletion{
public static Singletion singletion=new Singletion();
private Singletion(){
}
public static Singletion getInstance(){
return singletion;
}
}
---------------4月8号 代理模式
(1)代理模式
第一步:
/**
* 抽象角色
* @author Administrator
*
*/
public interface Action {
public void doaction();
}
第二步:
/**
* 真实角色
* @author Administrator
*
*/
public class ActionImpl implements Action {
@Override
public void doaction() {
System.out.println("找房子一室一厅");
}
}
第三步:
/**
*代理角色 相当中介
* @author Administrator
*
*/
public class ActionProxy implements Action {
private Action action;
public void setAction(Action action) {
this.action = action;
}
@Override
public void doaction() {
if(action!=null){
action.doaction();
}
}
}
第四步:
public class Test {
public static void main(String[] args) {
Action action =new ActionImpl();
ActionProxy proxy=new ActionProxy();
proxy.setAction(action);
proxy.doaction();
}
}
总结: 代理模式 把new对象全放在springIOC容器中 方便在外界管理
代理类 里面 是把接口放在类里面 实现接口的方法
-----生成日志的方法-------------------------------------------------------------------------
笨方法:
第一步: 在UserServiceImpl类里面
//日志对象
private Logger log=Logger.getLogger(UserServiceimpl.class);
第二步: 在登录login方法中调用
public User login(String userCode, String userPassword) {
log.info("调用了login方法 方法入参:"+userCode+","+userPassword);
User user = null;
try {
user = userDao.getLoginUser(userCode);
} catch (Exception e) {
log.info("发生了异常"+e.getMessage());
e.printStackTrace();
}
// 匹配密码
if (null != user) {
if (!user.getUserPassword().equals(userPassword))
user = null;
}
return user;
}
如何统一管理日志记录:(在业务里就写业务相关代码 专心在事情)
------------------------AOP知识点:---------------------------------------------
AOP:
所谓面向切面编程,
是一种通过预编译和运行期动态代理的方式实现在不修改源代码的情况下给程序动态添加功能的技术
AOP: 原理
将复杂的需求分解出不同方面,将散布在系统中的公共功能集中解决
采用代理机制组装起来运行,
在不改变原程序的基础上对代码段进行增强处理,增加新的功能
AOP可以用来处理:日志 权限 事务
实现AOP
注解方式将Bean的定义信息和Bean实现类结合在一起,Spring提供的注解有
@Component:实现Bean组件的定义
@Repository :用于标注DAO类
@Service :用于标注业务类
@Controller :用于标注控制器类
第一步:
导入四个jar包(三个重要的一个可有可无的)
第二步:
编写前置增强类
public class AopLogger {
//日志对象
private Logger log = Logger.getLogger(AopLogger.class);
//第二步 编写前置增强
public void before(JoinPoint jp) {// 连接点
log.info("调用了" + jp.getTarget() + "的方法" + jp.getSignature().getName()
+ ",方法入参: " + Arrays.toString(jp.getArgs()));
}
//第二步 编写后置增强
public void afterReturning(JoinPoint jp,Object returnResult) {// (连接点,返回结果类型)
log.info("调用了" + jp.getTarget() + "的方法" + jp.getSignature().getName()
+ ",方法入返回值: " + returnResult);
}
// 第二步 编写异常增强
public void afterThrowing(JoinPoint jp, Throwable e) {// (连接点,异常的父类)
log.info("异常:::调用了" + jp.getTarget() + "的方法" + jp.getSignature().getName()
+ ",方法异常: " + e);
}
// 第二步 编写环绕增强
public void arround(ProceedingJoinPoint jp) {
System.out.println("***环绕增强的开始*****");
log.info("环绕增强调用了" + jp.getTarget() + "的方法" + jp.getSignature().getName()
+ "方法参数是" + Arrays.toString(jp.getArgs()));
try {
jp.proceed();
} catch (Throwable e) {
log.info("环绕增强调用了" + jp.getTarget() + "的方法" + jp.getSignature().getName()
+ "异常类型:" + e);
}
System.out.println("***环绕增强的结束*****");
}
//第二步 编写最终增强
public void after(JoinPoint jp){
System.out.println("***after最终增强的开始*****");
log.info("调用了" + jp.getTarget() + "的方法" + jp.getSignature().getName()
+ "方法参数是" + Arrays.toString(jp.getArgs()));
System.out.println("***after最终增强的结束*****");
}
}
第三步 修改配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
">
第四步 :定义切入点
注意:dao-service层的组件不能少 不然的的话调用的时候会出现异常
--------这是普通的增强组件 下面还有注解常用的
<!-- 声明增强组件 -->
<bean id="aoplogger" class="cn.smbms.aop.AopLogger" />
<aop:config>-------AOP内容
<!-- 切入点 -->
<aop:pointcut id="pointcut" expression="execution(* cn.smbms.service.user..*.*(..))" />
<!-- 织入切面 -->
<aop:aspect ref="aoplogger">
<!-- 前置增强 在方法调用前调用前置增强 -->
<aop:before method="before" pointcut-ref="pointcut" />
<!-- 后置增强 -->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="returnResult" />
<!-- 异常增强 -->
<aop:after-throwing throwing="e" method="afterThrowing" pointcut-ref="pointcut" />
<!--环绕增强 -->
<aop:around method="arround" pointcut-ref="pointcut"/>
<!-- 最终增强 -->
<aop:after method="after" pointcut-ref="pointcut" />
</aop:aspect>
</aop:config>
五大增强方式:
1 前置增强: 《before》
<!-- 前置增强 在方法调用前调用前置增强-->
<aop:before method="before" pointcut-ref="pointcut"/>
2 后置增强 《after-returning》
after-returning:
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="returnResult"/>
如果代码中有异常则不会执行 必须成功执行方法后执行
3 异常增强 《after-throwing》
有异常发生的时候增强
4 环绕增强 《around》
在目标方法执行前执行后执行
<!--环绕增强 -->
<aop:around method="arround" pointcut-ref="pointcut" />
5 最终增强 《after》
在目标方法执行后执行 有异常也会执行
<!-- 最终增强 -->
<aop:after method="after" pointcut-ref="pointcut" />
*********注意的是环绕增强使用的是ProceedingJoinPoint(是Joinpoint子接口)连接点接口
1.切面(Aspect):切面就是一个关注点的模块化,如事务管理、日志管理、权限管理等;
2.连接点(Joinpoint):程序执行时的某个特定的点,在Spring中就是一个方法的执行;
3.通知(Advice):通知就是在切面的某个连接点上执行的操作,也就是事务管理、日志管理等;
4.切入点(Pointcut):切入点就是描述某一类选定的连接点,也就是指定某一类要织入通知的方法;
5.目标对象(Target):就是被AOP动态代理的目标对象;
AOP相关术语
增强处理(Advice)
前置增强
后置增强
环绕增强、异常抛出增强、最终增强等类型
切入点(Pointcut)
连接点(Join Point)
切面(Aspect)
目标对象(Target object)
AOP代理(AOP proxy)
织入(Weaving)
匿名内部类里面不能执行非final的变量 还有final修饰的全局变量要赋初始值
prepardstatment 的设置参数的下标是从1开始的
proceed()执行连接点的方法 也就是service层的方法
getTarget( )返回目标对象 也就是service层的对象
getsignature 返回目标方法 也是就是service的方法 在.getName()可以获得方法的名字
getArgs( )返回目标方法的实际参数 也可以当做数组 用Arrays.toString( )接受
------------------------4月9号知识点------------------
问题: 使用注解完成AOP增强类
推荐使用
(注意使用前一定在要在增强类里面加上@aspect )
(在配置文件中<aop:aspectj-autoproxy />:启用对于@AspectJ注解的支持
)
Spring在定义切面时提供了多种选择,应根据项目的具体情况做出选择:
1、如果项目采用JDK 5.0或以上版本,可以考虑使用@AspectJ注解方式,减少配置的工作量
2、如果不愿意使用注解或项目采用的JDK版本较低无法使用注解,
则可以选择使用<aop:aspect>配合普通JavaBean的形式
使用步骤:
1:写一个增强类
类上面加上
@Aspect //只是声明是一个Spring切面 和注解代替bean无关
@Component //代替在配置文件声明增强组件bean
public class AopLogger {
。。。。。。。。。。
}
2 类的方法里面
@Before("execution(* cn.smbms.service.user..*.*(..))") 《加上切入点》
public void before(JoinPoint jp) {// 连接点
log.info("前置增强调用了" + jp.getTarget() + "的方法" + jp.getSignature().getName()
+ ",方法入参: " + Arrays.toString(jp.getArgs()));
}
3 在配置文件中
<!-- 添加增强组件beans --> 《这个是用注解代替增强bean组件》
<context:component-scan base-package="cn.smbms.aop"></context:component-scan>
<!-- 开启@AspectJ-autoProxy -->
<aop:aspectj-autoproxy/>
代码练习
第一步: 编写增强组件
@Aspect //只是声明是一个Spring切面 和注解代替bean无关
@Component //注解 代替在配置文件声明增强组件bean
public class AopLogger {
// 日志对象
private Logger log = Logger.getLogger(AopLogger.class);
//每个方法都要写切入点麻烦所以用一个空方法代替 &&&&&&&&&&&&&&&&&&&&&&&&
@Pointcut(value="execution(* cn.smbms.service.user..*.*(..))")
public void pointcut(){}
// 第二步 编写前置增强
@Before("pointcut()")
public void before(JoinPoint jp) {// 连接点
log.info("前置增强调用了" + jp.getTarget() + "的方法" + jp.getSignature().getName()
+ ",方法入参: " + Arrays.toString(jp.getArgs()));
}
// 第二步 编写后置增强
@AfterReturning(pointcut="execution(* cn.smbms.service.user..*.*(..))",returning="returnResult")
public void afterReturning(JoinPoint jp, Object returnResult) {// (连接点,返回结果类型)
log.info("后置增强调用了" + jp.getTarget() + "的方法" + jp.getSignature().getName()
+ ",方法入返回值: " + returnResult);
}
// 第二步 编写异常增强
@AfterThrowing(pointcut="pointcut()",throwing="e")
public void afterThrowing(JoinPoint jp, Throwable e) {// (连接点,异常的父类)
log.info("异常增强:调用了" + jp.getTarget() + "的方法" + jp.getSignature().getName()
+ ",方法异常: " + e);
}
// 第二步 编写环绕增强
@Around(value="pointcut()")
public void arround(ProceedingJoinPoint jp) {
System.out.println("***环绕增强的开始*****");
log.info("环绕增强调用了" + jp.getTarget() + "的方法" + jp.getSignature().getName()
+ "方法参数是" + Arrays.toString(jp.getArgs()));
try {
jp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("***环绕增强的结束*****");
}
//第二步 编写最终增强
@After(value="pointcut()")
public void after(JoinPoint jp){
System.out.println("***after最终增强的开始*****");
log.info("最终增强调用了" + jp.getTarget() + "的方法" + jp.getSignature().getName()
+ "方法参数是" + Arrays.toString(jp.getArgs()));
System.out.println("***after最终增强的结束*****");
}
}
@Aspect 只是声明是一个Spring切面 和注解代替bean无关
@Component 注解 代替在配置文件声明增强组件bean
第二步:配置文件的配置
<!-- 添加数据访问层的组件 -->
<bean id="userDaoImpl" class="cn.smbms.dao.user.UserDaoImpl" />
<!-- 添加业务逻辑层的组件 -->
<bean id="userServiceImpl" class="cn.smbms.service.user.UserServiceImpl">
<property name="userDao" ref="userDaoImpl"/>
</bean>
<!-- 添加增强组件beans 也可以用注解完成-->
<context:component-scan base-package="cn.smbms.aop"></context:component-scan>
<!-- 开启@AspectJ-autoProxy -->
<aop:aspectj-autoproxy/>
AspectJ :面向切面的小框架 定义了AOP 语法,能够在编译期提供代码的织入
Spring通过集成AspectJ实现了以注解的方式定义增强类,大大减少了配置文件中的工作量
@AspectJ AspectJ 5新增的功能,使用JDK 5.0 注解技术和正规的AspectJ切点表达式语言描述切面
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
它的出现代替了basedao
--------Spring 对数据层的解决方法替代JDBC--------------
jdbcTemplate是core的核心类
主要作用完成资源创建以及释放工作
并且提供了PreparedStament回调函数供我们使用 把一些公共的与业务无关的帮我们实现了
自己理解的就是把数据源获得连接封装在Spring
第一步:一定要在lib里面添加
commons-pool-1.6.jar mysql.jar commons-dbcp-1.4.jar这三个jar包
使用jdbcTemplate 一定要有spring-jdbc-3.2.18.RELEASE.jar spring-tx-3.2.18.RELEASE.jar
第二步:
(1)编写dao层接口和实现类
@Resource //======autowrite 自动装配 先按名称找没有找到就按类型去找
列如:下面的是实现类
public class UserDaoImpl implements UserDao {
@Resource //======autowrite 自动装配 先按名称找没有找到就按类型去找
private JdbcTemplate jdbcTemplate;
//set访问器
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
/**
* 使用Spring 实现用户注册
* @param user
* @return
*/
@Override
public int saveUser(User user) {
String sql="insert into smbms_user (userCode,userName,userPassword) values(?,?,?)";
return jdbcTemplate.update(sql, user.getUserCode(),user.getUserName(),user.getUserPassword());
}
/**
* 使用Spring 实现用户登录
* @param user
* @return
*/
@Override
public User SpringUserLogin(String userCode) {
String sql="SELECT userCode,userName,userPassword FROM smbms_user WHERE userCode=?";
Object[] params={userCode};//传递参数
//调用userMapper的方法 把返回的结果集拿到此类中
return jdbcTemplate.queryForObject(sql, params, new UserMapper() );
}
}
----- (2)编写业务逻辑层的接口和实现类
列如业务的实现类
public class UserServiceImpl implements UserService {
// 使用Spring的控制反转 IOC来使项目变得可扩展
// 1 增加一个数据访问层的接口
private UserDao userDao; // ---------设值注入
// 2 添加一个set访问器
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
/**
* 用户的注册 使用Spring
*/
public boolean Springregister(User user){
if(userDao.saveUser(user)>0){
return true;
}
return false;
}
/**
* 使用Spring实现用户的登录
*/
@Override
public User SpringLogin(String userCode, String userPassword) {
User user = null;
try {
user = userDao.SpringUserLogin(userCode);
} catch (Exception e) {
e.printStackTrace();
}
// 匹配密码
if (null != user) {
if (!user.getUserPassword().equals(userPassword))
user = null;
}
return user;
}
}
注意&&&&&&&&&
注册使用的是
JdbcTemplate.update(String sql, Object... args)
登录使用的是
JdbcTemplate.queryForObject(String sql, Object[] args, RowMapper<User> rowMapper)
其实增删改用的都是update方法,而查询则是和query相关的方法。
返回集合可以用 query()方法
使用登录的话要加一个UserMannger类实现RowMapper<User>接口
public class UserMapper implements RowMapper<User> {
//相当于把返回的Result结果集 放在这个类里面实现
@Override
public User mapRow(ResultSet rs, int rows) throws SQLException {
User user=new User();
user.setUserCode(rs.getString(1));
user.setUserName(rs.getString(2));
user.setUserPassword(rs.getString(3));
return user;
}
}
第三步:
public static void main(String[] args) {
//配置文件的路径
String configLocation="applicationContext.xml";
//创建对象 读取配置文件 就有了spring容器组件
ApplicationContext context=new ClassPathXmlApplicationContext(configLocation);
//导入源码包
//从容器中取出来需要的组件 UserService.class利用泛型不需要强转了
UserService userService=context.getBean("userServiceImpl" ,UserService.class);
//最后就可以调用UserService接口的方法了
//User user=userService.login(" ", " ");
User user=new User("0000001","Spring测试注册","0000");
boolean flag=userService.Springregister(user);
if(flag){
System.out.println("ok");
}else{
System.out.println("no");
}
}
第三步:配置文件
<!-- 添加数据访问层的组件 -->
<bean id="userDaoImpl" class="cn.smbms.dao.user.UserDaoImpl" />
<!-- 添加业务逻辑层的组件 -->
<bean id="userServiceImpl" class="cn.smbms.service.user.UserServiceImpl">
<property name="userDao" ref="userDaoImpl" />
</bean>
<!-- 添加增强组件beans 也可以用注解完成 -->
<context:component-scan base-package="cn.smbms.aop,cn.smbms.dao.user"></context:component-scan>
<!-- 开启@AspectJ-autoProxy -->
<aop:aspectj-autoproxy />
<!-- 配置DBCP数据源组件 -->
<!-- 数据源连接池获得连接 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" >
<property name="driverClassName" value="com.mysql.jdbc.Driver">
</property>
<property name="url" value="jdbc:mysql://localhost:3306/smbms">
</property>
<property name="username" value="root" />
<property name="password" value="aptech" />
</bean>
<!-- 添加 jdbcTemplate组件-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
学完Spring应该有这样的意识:
其实在学Spring之后,感觉应该形成一种习惯,在new对象的时候我要想到IOC,在使用Set方法的时候,我要想到DI,再去要方便面(哦,不,是切面),我们应该想到用AOP的。这里可以在Spring中配置如下的引用链:
1. 我要有DataSource,DataSource的属性可以通过注入数据库的一些配置属性添加
2. 我要有JdbcTemplate,而Template依赖与DataSource,我要以ref的方式为我的JdbcTemplate注入引用
3. 有了JdbcTemplate之后,我要有Dao,此时我应该在Dao添加一个JdbcTemplate的成员,然后以ref的方式将JdbcTemplate引入到Dao中
4. 我在Action或者是Servlet中都会调用的是Serivce,所以,我在Serivce中要添加一个Dao作为成员,然后由ref在注入Dao到Service中
DataSource --> JdbcTemplate --> Dao --> Service --> Action/Servlet
"-->"表示将左边的对象注入到右边的对象当中
-------------------4月10号知识点--------------
利用Spring写好的AOP管理事务 这儿的知识点是用的Spring的jdbc里面的事务 以后可能还会用到 HIBERNATE的事务
事务管理器组件会根据DAO层框架的不同从而引用不同的组件
1 事务是放在业务逻辑层处理的
含义:事务是访问数据库的一个操作序列
2 事务:保证数据操作的一致性 完整性 有效性等
事务特性:传播性(6种) 隔离级(4种)
3 事务特征:4大特征 ACID( 原子性 一致性 隔离性 持久性)
4 事务出现原因:Spring为了解决各个技术的事务处理方式不一致 推出了事务的管理 从而简化管理和维护
5 事务优点:
1 为复杂的事务API提供一致的编程模型
2 支持声明式事务管理
3 支持Spring的各种数据访问抽象
------Spring3 声明式事务的使用步骤
《配置文件的形式进行声明式事务的处理》
第一步:配置文件要tx.jar 修改bean的命名空间 加上tx命名空间 还有验证文件tx
第二步:添加事务管理器组件
<!-- 创建事务管理器组件 -->
<bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>&&&&用的是配好的数据源
</bean>
第三步:配置事务增强 绑定事务管理器并针对不同方法定义事务规则
<tx:advice id="txAdvice" transaction-manager="TransactionManager">
<tx:attributes>
<!-- 针对不同方法定义不同事务规则 -->
<!--isolation隔离级 propagation传播性 (REQUIRED自动开启事务)-->
<!-- 查询的话不需要事务可以将事务read-only="true"propagation="SUPPORTS" 代表事务只可读 只有增删改才需要事务-->
<tx:method name="select*" isolation="DEFAULT" propagation="SUPPORTS" read-only="true"/>
<tx:method name="del/add/update*" isolation="DEFAULT" propagation="REQUIRED"></tx:method>
<tx:method name="SpringRegister2" propagation="REQUIRED" isolation="DEFAULT"></tx:method>
</tx:attributes>
</tx:advice>
第四步:
<aop:config>
<!-- 定义切入点 -->
<aop:pointcut expression="execution(* cn.smbms.service.user..*.*(..))" id="pointcut"/>
<!-- 新的织入方式 可以复用别人的代码-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
注意在使用事务的时候业务逻辑增删改的方法 一般在方法上添加throws Exception
/**
* 使用Spring测试事务的注册功能----------->业务接口
*/
public boolean SpringRegister2(User user) throws Exception;
/**
* 使用Spring测试事务的注册功能---------------》业务实现类
*/
public boolean SpringRegister2(User user)throws Exception {
boolean flag = false;
int i = 1 / 0;
int row = userDao.saveUser(user);
if (row > 0) {
flag = true;
}
return flag;
}
---------------------------《使用注解的形式进行声明式事务的处理》
第一步:创建事务管理器组件
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
第二步:开启注解式的声明事务
<tx:annotation-driven transaction-manager="transactionManager"/>
第三步:
(1)哪个类需要事务就在那个类加
@Transactional 表示声明这个类需要事务
然后所有的方法都可以使用注解式的声明事务了
( 2 ) 如果有方法(列如查询不需要)
可以在方法上面加上
@Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
表示这个方法不需要用事务而且传播机制是自身不会开启事务 只读
如果需要事务的话就不用加了它是有默认的
异常
NoSuchBeanDefinitionException
如果BeanFactory在Spring Context中没有找到bean的实例,就会抛出这个常见的异常。
关于事务的术语:
(1)propagation:事务传播机制
REQUIRED(默认值)方法被调用时自动开启事务,在事务范围内使用则使用同一个事务,否则开启新事务
REQUIRES_NEW 、(无论何时自身都会开启事务)
MANDATORY、(自身不开启事务,必须在事务环境使用否则报错)
NESTED(如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。需要JDBC3.0以上支持。)
SUPPORTS (自身不会开启事务,在事务范围内则使用相同事务,否则不使用事务)
NOT_SUPPORTED、(自身不会开启事务,在事务范围内使用挂起事务,运行完毕恢复事务)
NEVER(自身不会开启事务,在事务范围使用抛出异常)
(2)isolation:事务隔离等级
DEFAULT(默认值)
READ_COMMITTED
READ_UNCOMMITTED
REPEATABLE_READ
SERIALIZABLE
timeout:事务超时时间,允许事务运行的最长时间,以秒为单位。默认值为-1,表示不超时
read-only:事务是否为只读,默认值为false
rollback-for:设定能够触发回滚的异常类型
Spring默认只在抛出runtime exception时才标识事务回滚
可以通过全限定类名指定需要回滚事务的异常,多个类名用逗号隔开
rollback-for:设定能够触发回滚的异常类型
Spring默认只在抛出runtime exception时才标识事务回滚
可以通过全限定类名指定需要回滚事务的异常,多个类名用逗号隔开
------------------------4月11号SpringMvc
1 工作流程
配置文件头的设置
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
-----------------------------SpringMVC 配置步骤:
SpringMVC优势:
清晰地角色划分
灵活的配置功能
提供了大量的控制器接口和实现类
真正的View层实现无关(JSP、Velocity、Xslt等)
国际化支持
面向接口编程
1 导包 把下面所有包导入web-inf下面的lib里面
aopalliance-1.0.jar
aspectjweaver-1.6.9.jar
commons-logging-1.2.jar
log4j-1.2.17.jar
spring-aop-3.2.18.RELEASE.jar
spring-beans-3.2.18.RELEASE.jar
spring-context-3.2.18.RELEASE.jar
spring-core-3.2.18.RELEASE.jar
spring-expression-3.2.18.RELEASE.jar
spring-jdbc-3.2.18.RELEASE.jar
spring-tx-3.2.18.RELEASE.jar
spring-web-3.2.18.RELEASE.jar
spring-webmvc-3.2.18.RELEASE.jar
2 在web.xml配置Spring mvc 的前端配置控制器
<!-- 配置Spring前端控制器 核心DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 初始化一些参数 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 当web容器启动时就进行实例化 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置Springmvc映射 所有请求都会交给前端控制器 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
3 配置web的配置文件 springmvc-servlet.xml
(1) 添加一个映射处理器返回一个handler
<!-- SpringMVC默认的HandlerMapping(映射处理器)是BeanNameUrlHandlerMapping 也可以不写会默认找 -->
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
(2) 提供自定义页面控制器controller(需要自己定义类)
<!-- 将bean的name属性作为URL使用 自定义的控制器-->
<bean name="/index.html" class="cn.smbms.controller.IndexController"></bean>
<bean name="/index" class="cn.smbms.controller.IndexController"></bean>
<bean name="/index.do" class="cn.smbms.controller.IndexController"></bean>
<bean name="/666" class="cn.smbms.controller.IndexController"></bean>
这里不能带有jsp的后缀
(3) 提供视图解析器
<!-- 完成视图的对应 也就是渲染视图 -->
<!-- 对转向页面的路径解析。prefix:前缀, suffix:后缀 -->
<!--视图解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
(2)真实类
提供返回对象
设置显示在视图的数据
设置逻辑视图名------------------》要和
public class IndexController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest arg0,
HttpServletResponse arg1) throws Exception {
//提供返回对象
ModelAndView mv=new ModelAndView();
//设置显示在视图的数据
mv.addObject("msg","这是我的第一个SpringMVC程序");//有默认的request作用域
//设置逻辑视图名
mv.setViewName("index");
return mv;
}
}
4 创建真实的视图名 要和逻辑视图名保持一致
客户访问路径:http://localhost:8080/Spring_MVC0411/666
--------------------使用注解进行HandlerMapping添加处理器-----》推荐使用
(1)修改web.xml 添加一个控制器
<!-- 配置Spring前端控制器 核心DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 初始化一些参数 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 当web容器启动时就进行实例化 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置Springmvc映射 所有请求都会交给前端控制器 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
(2)在设置SpringMVC的配置文件
0 添加handlermapping处理器 可以默认不写会自动调用------》默认调用的是 BeanNameUrlHandlerMapping映射器
1 添加Spring Mvc注解支持
<mvc:annotation-driven/>
2 添加注解扫描包
<context:component-scan base-package="cn.smbms.controller"></context:component-scan>
3 视图解析器
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
(3)编写Controller类
1 在类上面加@Controller
2 在方法上面加@RequestMapping("/welcome")
@Controller //表示他是一个控制器组件 不用实现controller接口
public class WelcomeController{
@RequestMapping("/welcome")
public String doWlecome(){
//返回逻辑视图名
return "index";
}
}
视图解析器:
将逻辑视图的名字与JSP等视图技术进行匹配
SSM--->SpringMVC+Spring+Mybaties
MVC全名字:(Model view controller)
Model发展历史:
model1 jsp+javaBean
model2 jsp+servlet+javaBean
SpringMVC+Spring+jdbc(常见的开发架构)
自己查看<mvc:annotation-driven/>底层知识点
导类的全路径ctrl+shift+t
注解使用的映射处理器是 defaultannotationhandlerMapping
------------------------4月12号 参数传递
百度搜索HTTP状态码
400 请求参数有误 405 提交方式错误 500服务器错误
如何把View参数传递到Controller????? View to Controller -----以下有6种方法
注意 model模型里面的int 不传递值不会报错 默认是0
1 直接传递(直接定义参数名)
(1) 4个参数以内建议使用直接传递
(2)要求:前台传递的参数和Controller方法中的参数名字相同 如果不一样String类型的则获得null
(3)如果是integer传递一个“adc”则会出现类型转换异常
(4)报400异常:服务器解析不了
(5)必须使用基本数据的包装类 如果用户不填写 就是null 你写int类型 就会报错400 空值不能转化基本数据
代码练习1: 直接传递
@RequestMapping("/register.do")
public String doRegister(String userCode,String userPassWord){
//如果把View参数传递到Controller
System.out.println("账号"+userCode);
System.out.println("密码"+userPassWord);
return "index";
}
路径:localhost:8080/Spring_MVC0411/register.do?userCode=tom&userPassWord=0
代码练习2 :
//第一步先让用户去注册表单
@RequestMapping("goreg.do")
public String goRegister(){
return "register";
}
// 第二步获取 用户表单的内容
@RequestMapping("/register.do")
public String doRegister(String userCode,String userPassWord,Integer age){
//如何把View参数传递到Controller
直接传递
System.out.println("账号"+userCode);
System.out.println("密码"+userPassWord);
System.out.println("年纪"+age);
return "index";
}
访问 http://localhost:8080/Spring_MVC0411/goreg.do
2 使用注解@RequestParam 参数传递 --------------->推荐使用
value:表单name属性保持一致 也可以不加
required=true 必须传递参数否则报错
defaultValue="100"没有传递参数 默认100
第一步先让用户去注册表单
注意1 看类上面有没有@RequestMapping指定路径 有的话要类+方法
注意2 JSP表单提交也要加上类路径
@RequestMapping("goreg2.do")
public String goRegister2() {
return "register2";
}
第二步获取 用户表单的内容使用注解获取数据
@RequestParam可以同时设置提交方式 里面的value和表单name属性保持一致 也可以不加
@RequestMapping(value = "/register2.do", method = RequestMethod.POST)
public String doRegister2(@RequestParam(value = "code") String userCode,
@RequestParam(value = "pwd") String userPassWord,
@RequestParam(value = "age", required = false) Integer age) {
System.out.println("账号" + userCode);
System.out.println("密码" + userPassWord);
System.out.println("年纪" + age);
return "user/user"; // 说明是在jsp/user/user.jsp
}
注意::
value也可以不用加 直接使用Strign userCode和表单中的name属性保持一致
如果啥也么有填写 又用required必填 将会获得空字符串而不是null
通过@RequestMapping可以作用在类上面也可以在方法上 如果类上面有
那就是 类+方法才可以访问到
3 使用@RequestMapping--------------------------------
注意: 1 params={}带的参数必须和表单name属性一样
2 且前台控制器的方法上的参数也要和表单的name一样
3 表单的提交方式必须和前台控制器的提交方式保持一致 否则报405错误 必须是post get其他的不行
@RequestMapping("/goreg.do")
public String goReg(){
return "register";
}
@RequestMapping(value="/doreg.do",method=RequestMethod.POST,params={"userCode","userPassWord","age"})
public String doReg(String userCode,String userPassWord,Integer age){
System.out.println("账号" + userCode);
System.out.println("密码" + userPassWord);
System.out.println("年纪" + age);
return "/user/user";
}
4 使用传递实体类------------------
注意:1 实体属性必须有set访问器
2 实体属性值 必须和表单的name属性值一样 否则拿不到数据
好处:直接把从view封装成user对象我们不用再去封装了
@RequestMapping("/goreg.do")
public String goReg(){
return "register";
}
//String userCode,String userPassWord,Integer age
@RequestMapping(value="/doreg.do",method=RequestMethod.POST)
public String doReg(User user){
System.out.println("code="+user.getUserCode());
System.out.println("pwd="+user.getUserPassword());
return "/user/user";
}
5 使用原来的HttpServlertRequest 的Parameter()方法
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/goreg.do")
public String goReg(){
return "register";
}
//String userCode,String userPassWord,Integer age
@RequestMapping(value="/doreg.do",method=RequestMethod.POST)
public String doReg(HttpServletRequest request){
String code=request.getParameter("userCode");
String pwd=request.getParameter("userPassword");
String age=request.getParameter("age");
System.out.println(code+" "+pwd+" "+age);
return "/user/user";
}
}
数据绑定:处理器收集请求参数的方式
基本数据不传递参数 会报参数不存在异常
包装类不传递初始值null
------------------------4月13 --------------------------------
SpringMVC+Spring+JDBC
注意:
1 Controller默认单列模式 线程安全 不要在类里面放一些公用的变量 接口集合 用到的东西就放在方法里面
参数传递--------------------------------如何Controller to view 如何将模型数据传递给视图
1 使用ModelAndView 的addObject(" K", V)方法 包含视图信息和模型数据信息
设置模型数据 K-V mv.addObject("userlist", list);
设置视图:1 setView(View view) / 2 setViewName(String viewName)
代码列如:
@RequestMapping(value = "userlist.do", method = RequestMethod.GET)
public ModelAndView searchUserList() { //如何将模型的数据提取出来
List<User> list = new ArrayList<User>();
list.add(new User(1001, "mayun1", "马云1"));
list.add(new User(1002, "mayun2", "马云2"));
list.add(new User(1003, "mayun3", "马云3"));
list.add(new User(1004, "mayun4", "马云4"));
list.add(new User(1005, "mayun5", "马云5"));
ModelAndView mv = new ModelAndView("user/userlist");
// 设置模型数据 K-V
mv.addObject("userlist", list);
return mv;
}
<h1>用户列表</h1>
<c:forEach items="${userlist }" var="user">
<p>${user.id }--------${user.userCode }------${user.userName }</p>
</c:forEach>
2 推荐使用Model
数据结构:Map类型
常用方法:添加模型数据
在Model中增加模型数据,若不指定key,
则默认使用对象的类型作为key
代码练习
@RequestMapping(value = "userlist2.do", method = RequestMethod.GET)
public String searchUserList2(Model model) { //import org.springframework.ui.Model;
List<User> list = new ArrayList<User>();
list.add(new User(1001, "mayun1", "马云1"));
list.add(new User(1002, "mayun2", "马云2"));
list.add(new User(1003, "mayun3", "马云3"));
list.add(new User(1004, "mayun4", "马云4"));
list.add(new User(1005, "mayun5", "马云5"));
//添加模型数据
model.addAttribute("userlist", list);
//返还逻辑视图
return "user/userlist";
}
3 使用map集合
@RequestMapping(value = "userlist3.do", method = RequestMethod.GET)
public String searchUserList3(Map<String, Object> map) { //import org.springframework.ui.Model;
List<User> list = new ArrayList<User>();
list.add(new User(1001, "mayun1", "马云1"));
list.add(new User(1002, "mayun2", "马云2"));
list.add(new User(1003, "mayun3", "马云3"));
list.add(new User(1004, "mayun4", "马云4"));
list.add(new User(1005, "mayun5", "马云5"));
map.put("userlist", list);
return "user/userlist";
}
--------------项目整合步骤--------------------------------------
第一步: 导包 (没导入完会报ClassNotFindException异常)
aopalliance-1.0.jar
aspectjweaver-1.6.9.jar
commons-dbcp-1.4.jar
commons-logging-1.2.jar
commons-pool-1.6.jar
log4j-1.2.17.jar
login.jsp
mysql.jar
spring-aop-3.2.18.RELEASE.jar
spring-beans-3.2.18.RELEASE.jar
spring-context-3.2.18.RELEASE.jar
spring-core-3.2.18.RELEASE.jar
spring-expression-3.2.18.RELEASE.jar
spring-jdbc-3.2.18.RELEASE.jar
spring-tx-3.2.18.RELEASE.jar
spring-web-3.2.18.RELEASE.jar
spring-webmvc-3.2.18.RELEASE.jar
第二步:配置文件
(1) 配置spring文件----------------------
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
">
<!-- 使用注解开启Spring容器 -->
<context:component-scan base-package="cn.smbms.service,cn.smbms.dao" />
<!-- 开启@AspectJ注解的支持 -->
<aop:aspectj-autoproxy />
<!-- 配置DBCP数据源组件 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/smbms" />
<property name="username" value="root" />
<property name="password" value="aptech" />
</bean>
<!-- 创建JdbcTemplate组件 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 创建事务管理器组件 -->
<!-- 事务管理器组件会根据Dao层框架的不同从而引用不同的组件 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置事务增强 绑定事务管理器并针对不同方法定义事务规则 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 针对不同方法定义事务规则 -->
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="search*" propagation="SUPPORTS" read-only="true" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<!-- 定义切面 -->
<aop:config>
<!-- 定义切入点 -->
<aop:pointcut id="pointcut"
expression="execution(* cn.smbms.service..*.*(..)) " />
<!-- 织入 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
</beans>
(2) 配置springmvc文件(注意加入静态资源的访问)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
">
<!-- 添加Spring MVC注解支持 -->
<mvc:annotation-driven />
<!-- 添加注解的扫描包 -->
<context:component-scan base-package="cn.smbms.controller" />
<!-- 添加静态资源的访问 -->
<mvc:resources location="/statics/" mapping="/statics/**"/>
<!-- 视图解析器 -->
<!-- 将逻辑视图的名字与JSP等视图技术进行匹配 -->
<!-- 对转向页面的路径解析。prefix:前缀, suffix:后缀 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
(3) web.xml (注意监听器 上下文参数)
<welcome-file-list>
<welcome-file>/WEB-INF/jsp/login.jsp</welcome-file>
</welcome-file-list>
<!-- 上下文参数 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-*.xml</param-value>
</context-param>
<!-- 加载监听器,启动Spring容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--配置Spring MVC的前端控制器 DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 初始化参数 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 当Web容器启动时加载DispatcherServlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有的请求都会交给Spring MVC的前端控制器 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
database.properties
log4j.properties
第二步:改造dao层 @Repository
第三步:改造Service层 @Service
@Resource
第三步:改造Controller层
创建UserController,
实现以下业务功能:
跳转到系统登录页
实现登录
第四步:改造View层
静态资源文件(js、css、images等)
用户登录页面login.jsp
系统首页frame.jsp( head.jsp 、foot.jsp)
转发与重定向
“redirect:” --》 重定向
“forward:”--》 转发 默认的是转发
---------问题:静态资源文件的引用
<mvc:resources/>标签
mapping:将静态资源映射到指定的路径下
location:本地静态资源文件所在的目录
-----------------4月14号知识点--------------------
第一个:知识点
为了防止出现EmptyResultDataAccessException查不到数据 可以在dao层加一个try-catch 增加软件健壮性
public User getLoginUser(String userCode) throws Exception {
User user = new User();
String sql = "select * from smbms_user where userCode=?";
Object[] params = { userCode };
try {
user=jdbcTemplate.queryForObject(sql,params,new UserMapper());
} catch (Exception e) {
return null;
}
return user;
}
-----------异常的处理--------------------------
局部异常处理:
步骤:加注解@ExceptionHandler+自定义异常处理方法
@ExceptionHandler //局部异常处理
public String handlerException(RuntimeException e,HttpServletRequest request){
request.setAttribute("errorMsg", "系统发生异常");
return "error";
}
本类某个方法发生异常的时候就会执行该方法
全局异常:
步骤:在springmvc 配置文件中 加入bean
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.RuntimeException">error</prop>
</props>
</property>
</bean>
key代表执行的异常 error代表映射的页面 默认加上前缀后缀
然后在view可以显示错误的方法
可以在可能发生异常的方法catch中 throw new RuntimeException("登录失败");
----------------注销的实现小方法
1 用户点击退出通过映射 进入此方法
@RequestMapping("/jsp/logout.do")
public String LoginOut(HttpSession session){
session.removeAttribute("userSession");//清除session
return "redirect:tologin.do";//重定向到登录界面
}
2 然后在利用重定向进入login.jsp中
@RequestMapping("/jsp/tologin.do")
public String goLogin(){
return "login";
}
--------------------------------------4月16号
1 问题: 类上面的@RequestMapping("/user")是和虚拟URL相关 和return 逻辑视图名无关
------------------------------4月17号 文件上传 数据校验
1 :修改过js脚本可以清理下浏览器缓存
Spring MVC框架中时间类型的数据无法自动绑定
2 Date时间类型的使用 实体类 参数绑定 直接拿值拿不到
可以
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birthday; //出生日期
3<!-- 编写过滤器解决字符编码问题 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4 数据校验(服务器端的数据校验)可以使用JSR 303
JSR 303:Java为Bean数据合法性校验所提供的标准框架
JSR 303通过在Bean属性上标注校验注解指定校验规则,并通过标准的验证接口对Bean进行验证
第一步:添加jar包
第二步:修改User类
第三步:修改controller
第四步:修改视图view 使用<fm:errors/>标签在JSP页面显示错误信息
@RequestMapping(value="saveuser.do",method=RequestMethod.POST)
public String addUserSave(@Valid User user,BindingResult bindingresult,HttpSession session){
if(bindingresult.hasErrors()){
//有错误 没有通过校验
return "user/useradd";
}
user.setCreationDate(new Date());
User temp=(User)session.getAttribute("userSession");
user.setCreatedBy(temp.getId());
try {
userservice.add(user);
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:user/userlist.do";
}
@Valid注解标示的参数后面,必须紧挨着一个BindingResult参数,否则Spring会在校验不通过时直接抛出异常
5 spring标准标签库 类似java标准标签库
第一步必须在JSP页面的开头处声明taglib指令
<%@ taglib prefix="fm"
uri="http://www.springframework.org/tags/form" %>
6 参数传递 使用REST风格(Representational State Transfer)
含义:表述性状态转移,是一种软件架构风格
使用步骤:
第一步:RequestMapping里面加URL{xxx}占位符参数
第二步: 加注解@PathVariable接收REST风格URL中的参数
@RequestMapping("/viewuser/{id}")
public String viewUser(@PathVariable String id,Model model){
System.out.println("接受REST风格的参数"+id);
return "user/userview";
}
http://localhost:8090/SMBMS_C11_05/user/view/12
7 使用
return jdbcTemplate.queryForObject(sb.toString(), params,Integer.class);
返回的是int类型
----------------------------------------4月18号 单文件上传 -- 多文件上传
MultipartFile类常用的一些方法:
1 String getContentType() //获取文件MIME类型
2 InputStream getInputStream() //后去文件流
3 String getName() //获取表单中文件组件的名字
4 String getOriginalFilename() //获取上传文件的原名
5 long getSize() //获取文件的字节大小,单位byte
6 boolean isEmpty() //是否为空
7 void transferTo(File dest) //保存到一个目标文件中。
单文件上传
1 导包(3个 2个必须的)
commons-io-2.4.jar
commons-fileupload-1.2.2.jar
2 必须条件
表单必须是post
form加属性 enctype="multipart/form-data"
3在spring-mvc修改配置文件 配置MultiResolver的bean实例
<bean id="multipartResolver" class=" org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 上传文件的最大值 单位byte -->
<property name="maxUploadSize" value="50000000"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
4 修改Controllet
处理单个多文件表单的处理
// 保存用户
@RequestMapping(value = "saveuser.do", method = RequestMethod.POST)
public String addUserSave(
User user,
HttpSession session,
@RequestParam(value = "a_idPicPath", required = false) MultipartFile attach,
HttpServletRequest request) {
String uploadPath = session.getServletContext().getRealPath(
"statics" + File.separator + "uploadfiles");
// 证件照的路径
String idPicPath = null;
// 实现文件上传
if (!attach.isEmpty()) {
String fileName = attach.getOriginalFilename();
String extend = FilenameUtils.getExtension(fileName);
// 获取文件的大小
long size = attach.getSize();
if (size > 500000) {
request.setAttribute("errorInfo", "文件大小不能超过500kb");
return "user/useradd";
} else if ("jpg".equalsIgnoreCase(extend)
|| "png".equalsIgnoreCase(extend)) {
fileName = UUID.randomUUID().toString() + "." + extend;
File targetFile = new File(uploadPath, fileName);
if (!targetFile.exists()) {
targetFile.mkdirs();
}
try {
attach.transferTo(targetFile);
idPicPath = "statics" + File.separator + "uploadfiles"
+ File.separator + fileName;
} catch (Exception e) {
request.setAttribute("errorInfo", "上传失败");
return "user/useradd";
}
} else {
request.setAttribute("errorInfo", "上传文件类型必须为:jpg、jpeg、png、pneg");
return "user/useradd";
}
}
try {
user.setCreationDate(new Date());
// 从会话信息中取出用户对象
User temp = (User) session.getAttribute("userSession");
user.setCreatedBy(temp.getId());
// 设置证件照的路径
user.setIdPicPath(idPicPath);
userService.add(user);
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:/user/userlist.do";
}
--------------------------4月20号 JSON对象的处理 数据转换和格式化
修改js文件过要清理下缓存 因为之前的js会有缓存
常用方法: JSONArray.toJSONString(HashMap);
JSON.toJSONString(user);
第一步:导包 fastjson-1.2.13.jar
第二步: 方法返回值object(json对象)
必须在方法上方加上注解@ResponseBody
作用:将标注该注解的处理方法的返回结果直接写入HTTP Response Body中,一般会在异步获取数据时使用
-----解决使用ajax中文乱码问题
原因: 消息转换器(StringHttpMessageConverter)中固定了转换字符编码为“ISO-8859-1”
解决方法一:
在方法上加注解@RequestMapping(value="viewuser.json",produces={"application/json;charset=utf-8"})
要注意:
请求报文头(viewuser.json)的Accept?须与响应报文头中的Content-Type?类型一致,即:application/json
produces的作用是指定返回的内容类型为json格式数据,并且字符串的转换编码为?“UTF-8”
解决方法二
修改springmvc配置文件: 加一个消息转换器
在 添加Spring MVC注解支持的时候解决
<mvc:annotation-driven >
<!-- 当使用ajax的时候会出现中文乱码 这个步骤就是解决乱码 -->
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
------------实现 不能同时注册相同名字的 功能
代码练习1
@RequestMapping("ucexist.html")
@ResponseBody //做ajax异步请求必须加这个注解
public Object userCodeIsExist(@RequestParam String userCode){
//返回的结果对象
HashMap<String, String> resultMap=new HashMap<String, String>();
if(StringUtils.isNullOrEmpty(userCode)){
resultMap.put("userCode", "exist");
}else{
//从数据库中判断是否存在
User user=null;
try {
user=userService.selectUserCodeExist(userCode);
if(user==null){
resultMap.put("userCode", "noexist");
}else{
resultMap.put("userCode", "exist");
}
} catch (Exception e) {
e.printStackTrace();
}
}
return JSONArray.toJSONString(resultMap);//一定是toJsonString
}
---------------js
userCode.bind("blur",function(){
//ajax后台验证--userCode是否已存在
$.ajax({
type:"GET",//请求类型
url:path+"/user/ucexist.html",//请求的url
data:{userCode:userCode.val()},//请求参数
dataType:"json",//ajax接口(请求url)返回的数据类型
success:function(data){//data:返回数据(json对象)
if(data.userCode == "exist"){//账号已存在,错误提示
validateTip(userCode.next(),{"color":"red"},imgNo+ " 该用户账号已存在",false);
}else{//账号可用,正确提示
validateTip(userCode.next(),{"color":"green"},imgYes+" 该账号可以使用",true);
}
},
error:function(data){//当访问时候,404,500 等非200的错误状态码
validateTip(userCode.next(),{"color":"red"},imgNo+" 您访问的页面不存在",false);
}
});
注意:不可以使用submit 提价表单了 用它就直接提交表单了 不走ajax了 应该使用button
---------功能2 实现点击查看显示用户详情
//写完可以先测试
//问题 中文乱码 方法1 方法 2 (修改配置文件) 时间问题
@RequestMapping(value="viewuser.json",produces={"application/json;charset=utf-8"})
@ResponseBody
public Object viewUser(@RequestParam String id) throws Exception{
String json="";
if(StringUtils.isNullOrEmpty(id)){
return "nodata";
}else{
User user=userService.getUserById(id);
if(user!=null){
json=JSON.toJSONString(user);
}
}
return json;
}
-----------------js中
$.ajax({
type:"GET",//请求类型
url:path+"/user/viewuser.json",//请求的url
data:{id:$(".hidden").val()},//请求参数
dataType:"json",//ajax接口(请求url)返回的数据类型
success:function(data){//data:返回数据(json对象)
$(".providerAdd").show();
$("#1").html(data.userCode);
$("#2").html(data.userName);
if(data.gender==1){
$("#3").html("男");
}
if(data.gender==2){
$("#3").html("女");
}
$("#4").html(data.birthday);
$("#5").html(data.phone);
$("#6").html(data.address);
$("#7").html(data.userRoleName);
},
});
------------------------------4月23号-------------JSON时间格式问题-----
问题:用户修改密码 和用户查看功能
问题:JSON数据的时间类型 JSON时间格式化问题
方法一:
在pojo类上面类的属性上面加入
@DateTimeFormat(pattern="yyyy-MM-dd") //view--->controller拿时间类型的数据
@JSONField(format="yyyy-MM-dd") //解决ajax使用JSON时间戳问题
private Date birthday; //出生日期
注意@DateTimeFormat和@JSONField注解的区别
方法二: 加消息转换器
<!-- 添加Spring MVC注解支持 -->
<mvc:annotation-driven >
<!-- 消息转换器 -->
<!-- 当使用ajax的时候会出现中文乱码 这个步骤就是解决乱码 -->
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
<property name="features">
<list>
<value>WriteDateUseDateFormat</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
然后controller里面写配套的
// 写完可以先测试
// 问题 中文乱码 方法1 方法 2 (修改配置文件) 时间问题
@RequestMapping(value = "viewuser.json", produces = { "application/json;charset=utf-8" })
@ResponseBody
public User viewUser(@RequestParam String id) throws Exception {
User user = null;
if (StringUtils.isNullOrEmpty(id)) {
return null;
} else {
user = userService.getUserById(id);
}
return user;
}
这个方法直接返回User就行了 不用再返回json了
如果同时配置了消息转换器和 注解 则默认注解优先 只显示年月日
--------------------配置 多视图解析器
第一步修改springmvc配置文件
<!-- 多视图解析器 -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver ">
<!-- 支持参数匹配 不写默认就是true-->
<property name="favorParameter" value="true"></property>
<!-- 请求映射的列表 -->
<property name="mediaTypes">
<map>
<entry key="html" value="text/html;charset=UTF-8"></entry>
<entry key="json" value="application/json;charset=UTF-8"></entry>
</map>
</property>
<!-- 网页解析器 -->
<property name="viewResolvers">
<list>
<!-- 内部bean 将原来的视图解析器引用过来 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</list>
</property>
</bean>
配置完后再使用ajax的话就不用带有中文乱码的消息转换器 只保留一个Date时间类型的消息转换器就行了
并且请求头 也可以使用html了
------------------SpringMVC的转换器------------------处理Date和Double类型的数据
------------------springmvc 处理不了Date类型和double类型的数据(view--controller的时候)
方法一:可以在User类的属性上面加@DateTimeFormat(pattern="yyyy-MM-dd")
方法二:自定义转换器
步骤
第一步:先在springmvc配置文件上加
第二步:在配置文件中的<mvc:annotation-driven conversion-service="myConversionService">
加入对自定义注解的引用
第三步:编写工具类实现Converter<String, Date>
<!-- 自定义转换器 -->
<bean id="myConversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="cn.smbms.tools.StringToDateConverter">
<constructor-arg value="yyyy-MM-dd"/>
</bean>
</list>
</property>
</bean>
<!-- 添加Spring MVC注解支持 -->
<mvc:annotation-driven conversion-service="myConversionService">
Converter 位于:import org.springframework.core.convert.converter.Converter;包中
类public class StringToDateConverter implements Converter<String, Date> {
private String datePattern;// 日期格式的字符串
public StringToDateConverter(String datePattern) {
this.datePattern = datePattern;
}
@Override
public Date convert(String str) {
Date date = null;
try {
SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
date = sdf.parse(datePattern);
} catch (ParseException e) {
// e.printStackTrace();
date = null;
}
return date;
}
}
方法三:编写一个普通类baseController 哪个Conteoller使用就用那个controller去extends
在方法里面进行数据格式的转换
WebDataBinder类位于 org.springframework.web.bind.WebDataBinder
/**
* 公共功能的Controller
*/
public class BaseConterller {
@InitBinder
public void InitBinder(WebDataBinder dataBinder) {
dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(
new SimpleDateFormat("yyy-MM-dd"), true));
}
}
------代码练习 用户密码的修改
第一步:编写dao-service
第二步:编写controller
/**
* 从head.jsp点击修改密码进入修改密码页面
*/
@RequestMapping("/pwdmodify.do")
public Object updatePwd() {
return "user/pwdmodify";
}
/**
* 表单提交到update.do执行处理修改密码过程
*/
@RequestMapping("/update.do")
public String DoupdatePwd(@RequestParam String newpassword,
HttpSession session, HttpServletRequest request) {
boolean flag=false;
// 从会话中拿到已登录的用户
User user = (User) session.getAttribute("userSession");
if (user == null) {
request.setAttribute("message", "当前用户未登录或者session已过期,请重新登录");
} else {
try {
flag = userService.UpdatePwd(user.getId(), newpassword);
System.out.println(newpassword);
System.out.println(user.getId());
System.out.println(flag);
} catch (Exception e) {
e.printStackTrace();
}
if (flag) {
return "login";
} else {
request.setAttribute("message", "修改密码失败");
}
}
return "/user/pwdmodify";
}
/**
* 使用ajax处理异步问题 :没有填写 get方式进入 和老密码做匹配 不一样就组织提交
*/
@RequestMapping("/chekOldPwd.json")
@ResponseBody
public Object chekOldPwd(@RequestParam String oldpassword,
HttpSession session) {
Map<String, String> map = new HashMap<String, String>();
if (StringUtils.isNullOrEmpty(oldpassword)) {
map.put("result", "error");
} else {
User user = (User) session.getAttribute("userSession");
if (user == null) {
map.put("result", "sessionerror");
} else {
String pwd = user.getUserPassword();
if (pwd.equals(oldpassword)) {
map.put("result", "true");
} else {
map.put("result", "fasle");
}
}
}
return JSONArray.toJSONString(map);
}
------------------js中
oldpassword.on("blur",function(){
$.ajax({
type:"GET",
url:path+"/user/chekOldPwd.json",
data:{method:"pwdmodify",oldpassword:oldpassword.val()},
dataType:"json",
success:function(data){
if(data.result == "true"){//旧密码正确
validateTip(oldpassword.next(),{"color":"green"},imgYes,true);
}else if(data.result == "fasle"){//旧密码输入不正确
validateTip(oldpassword.next(),{"color":"red"},imgNo + " 原密码输入不正确",false);
}else if(data.result == "sessionerror"){//当前用户session过期,请重新登录
validateTip(oldpassword.next(),{"color":"red"},imgNo + " 当前用户session过期,请重新登录",false);
}else if(data.result == "error"){//旧密码输入为空
validateTip(oldpassword.next(),{"color":"red"},imgNo + " 请输入旧密码",false);
}
},
error:function(data){
//请求出错
validateTip(oldpassword.next(),{"color":"red"},imgNo + " 请求错误",false);
}
});
------------------4月24号 mybatis框架知识点--------------------------------
注意mybatis使用的事务是<transactionManager type="JDBC"></transactionManager> JDBC事务管理
需要程序猿自己提交事务 所以删除修改插入都需要事务的操作
SqlSessionFactoryBuilder----》( build() )---》SqlSessionFactory
---》(openSession(true)代表自动提交false代表手动提交事务)---SqlSession
InputStream is = Resources.getResourceAsStream(resource);流的获得
SqlSession的常用方法:
在main方法中使用的
int count=session.selectOne("cn.smbms.dao.user.UserMapper.count");
List<User> list=session.selectList("cn.smbms.dao.user.UserMapper.getUserList");
在sercice层
count=session.getMapper(UserMapper.class).count();
list=session.getMapper(UserMapper.class).getUserList();
使用的getMapper(dao层.class).dao层的方法 --------------》反射机制
持久化的解决方案 :io流 jdbc
io流 输出流---》文件--》输出流
jdbc 对象模型--》关系模型(数据库)---》对象模型
ORM 对象关系映射:对象模型和关系模型相互转换的过程
ORM 的解决方案
(1)JDBC
( 2 ) Hibernate
(3)Mybatis
( 4 )jdo
mybatis 含义 数据库持久层(orm)的框架 把实体类和sql语句之间建立了映射关系
mybatis 特点
小巧灵活
是半自动的映射框架
mybatis的使用步骤
第一步:导包 (一个重要的 其他的都是依赖包)
asm-3.3.1.jar
cglib-2.2.2.jar
commons-logging-1.1.1.jar
javassist-3.17.1-GA.jar
log4j-1.2.17.jar
mybatis-3.2.2.jar---------》其余都是它的依赖包
mysql.jar
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar
第二步:放入mybatis的配置文件
第三步:创建实体类 和usermapper接口
第四步:在src资源包下面加入映射文件UserMapper.xml文件
第五步:可以测试下
public static void main(String[] args) {
SqlSession session=null;
try {
// 读取配置文件为流 创建实例把流读取返回一个sqlsessionfactory
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(is);
session = factory.openSession();
int count=session.selectOne("cn.smbms.dao.user.UserMapper.count");
System.out.println("用户总行数"+count);
} catch (IOException e) {
e.printStackTrace();
}finally{
if(session!=null){
session.close();
}
}
此过程注意 通过mybatis-config.xml--》以文件的形式(不能写点是斜杠)映射到cn/smbms/dao/user/UserMapper.xml下面的UserMapper.xml
找到命名空间通过id找到唯一的sql语句并执行
使用mybatis的优点
1 减少了61%的代码量
2 最简单的持久化框架
3 架构级性能增强
4 sql语句从代码中分离可重用
5 增强了项目中的分工
6 增强了移植性
使用mybatis的缺点
移植性差 是半自动化的 需要程序员精通sql语句的编写
sqlsessionfactorybuilder 是用过及丢 存在于方法内部
sqlsession不是线程安全的 单列的 生命周期不是永久的在每一次使用的时候都需要创建他
解决线程安全问题?(放在request作用域)
为了保证sqlsession是唯一的 可以建一个工具类 里面获得sqlsession 读取配置文件 这样测试类就可以简单优化
----工具类 读取配置文件 获得sqlsession 关闭连接
public class MyBatisUtil2 {
private static SqlSessionFactory factory;
static {
try {
// 读取配置文件为流 创建实例把流读取返回一个sqlsessionfactory
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
if (factory != null) {
return factory.openSession();
}
return null;
}
public static void closeSqlsession(SqlSession session) {
if (session != null) {
session.close();
}
}
}
这样操作的话 test类 就可以简化了----
public static void main(String[] args) {
SqlSession session=null;
try {
// 读取配置文件为流 创建实例把流读取返回一个sqlsessionfactory
session=MyBatisUtil2.getSqlSession();
int count=session.selectOne("cn.smbms.dao.user.UserMapper.count");
System.out.println("用户总行数"+count);
} catch (Exception e) {
e.printStackTrace();
}finally{
MyBatisUtil2.closeSqlsession(session);
}
}
------Mapper XML配置的顺序
configuration 中的顺序层次结构
1 properties 通过这个配置文件完成mybatis与数据库的连接
2 settings 设置MyBatis的行为 延迟加载等等
<settings>
<setting name="logImpl" value="LOG4J" />
</settings>
<settings>
<setting name="lazyLoadingEnabled" value="false" />
</settings>
3 typeAliases 类型别名
可以分为单个和统一包扫描
<typeAliases>
<!-- <typeAlias alias="user" type="cn.smbms.pojo.User"/> -->
<!-- 如果user过多可以扫描包 -->
<package name="cn.smbms.pojo" />
</typeAliases>
4 typeHandlers
5 objectFactory
6 plugins
7 environments 运行环境
按以上顺序编写
在实际开发中编写的顺序
1 把sql语句放在UserMapper.xml文件中
dao层更改为UserMapper 和配置文件名一样
里面的方法也要和xml文件中的ID保持一致
public interface UserMapper {
public int count();--------------------方法名和xml的id值保持一致
public List<User> getUserList();--------------------方法名和xml的id值保持一致
}
2 UserServiceImpl类里面的方法
public List<User> findAllUser() {
List<User> list=new ArrayList<User>();
SqlSession session=null;
try {
// 读取配置文件为流 创建实例把流读取返回一个sqlsessionfactory
session=MyBatisUtil2.getSqlSession();
list=session.getMapper(UserMapper.class).getUserList();
} catch (Exception e) {
e.printStackTrace();
}finally{
MyBatisUtil2.closeSqlsession(session);
}
return list;
}
注意 SqlSession使用的方法是反射的获取Dao层的方法
session.getMapper(UserMapper.class).getUserList();
dao接口里面的方法名要和xml文件的id保持一致 接口名要和xml的名字一样
---------------综上可得的配置文件
------------mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 通过这个配置文件完成mybatis与数据库的连接 -->
<configuration>
<!-- 引入 database.properties 文件-->
<properties resource="database.properties"/>
<!-- setting 设置MyBatis的行为 延迟加载等等 -->
<!-- 配置mybatis的log实现为LOG4J -->
<!-- <settings>
<setting name="logImpl" value="LOG4J" />
</settings> -->
<settings>
<setting name="lazyLoadingEnabled" value="false" />
</settings>
<!-- 类型别名 -->
<typeAliases>
<!-- <typeAlias alias="user" type="cn.smbms.pojo.User"/> -->
<!-- 如果user过多可以扫描包 -->
<package name="cn.smbms.pojo" />
</typeAliases>
<!-- 运行环境 -->
<environments default="development">
<environment id="development">
<!--配置事务管理,采用JDBC的事务管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- POOLED:mybatis自带的数据源,JNDI:基于tomcat的数据源 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 添加映射文件 不能写点它是以文件方式配置-->
<!-- 将mapper文件加入到配置文件中 -->
<mappers>
<mapper resource="cn/smbms/dao/user/UserMapper.xml"/>
</mappers>
</configuration>
---------UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 命名空间 -->
<mapper namespace="cn.smbms.dao.user.UserMapper">
<!-- 查询用户表记录数 -->
<select id="count" resultType="int">
select count(1) as count from smbms_user
</select>
<select id="getUserList" resultType="User">
select id from smbms_user
</select>
</mapper>
-------- ------------------------4月25号知识点------------------------------------------------
resultType SQL语句返回值类型的完整类名或别名
parameterType 传入SQL语句的参数类型
resultType :直接表示返回类型
resultMap :对外部resultMap的引用
POJO类的属性一定要和数据库的字段名保持一致 如果不一致则需要给字段 起别名
总结:
Mybatis 映射文件中参数的传递
(1)简单的数据类型 参数只能传递一个
(2)复杂的数据类型 参数超过4个 封装成对象进行传递
(3)复杂的数据类型 参数超过4个 封装成Map集合进行传递
(4)参数在4个以内 使用注解 @param解决参数传递问题
parameterType
基础数据类型
int、String、Date等
只能传入一个,通过#{参数名}即可获取传入的值
复杂数据类型
Java实体类、Map等
通过#{属性名}或者#{map的keyName}即可获取传入值
<!-- 根据用户名进行模糊查询 单个参数-->
<select id="getListByUserName" resultType="User" parameterType="string">
SELECT u.* ,r.roleName
FROM smbms_user u,smbms_role r
WHERE u.userRole=
r.id
AND userName LIKE CONCAT('%',#{userName},'%')
</select>
public List<User> getListByUserName(String userName);
<!-- 根据用户名进行模糊查询 俩个参数通过User-->
<select id="getUserListByUserNameAndRole" resultType="User" >
SELECT u.* ,r.roleName FROM smbms_user u,smbms_role r
WHERE u.userRole= r.id
AND userName LIKE CONCAT('%',#{userName},'%')
AND u.userRole=#{userRole}
</select>
public List<User> getUserListByUserNameAndRole(User user );
<!-- 根据用户名进行模糊查询 俩个参数 通过Map-->
<select id="getUserListByMap" resultType="User" >
SELECT u.* ,r.roleName FROM smbms_user u,smbms_role r
WHERE u.userRole= r.id
AND userName LIKE CONCAT('%',#{uName},'%')
AND u.userRole=#{uRole}
</select>
public List<User> getUserListByMap(Map<String, String> map );
!-- 根据用户名进行模糊查询 俩个参数 通过注解-->
<select id="getUserListByparam" resultType="User" >
SELECT u.* ,r.roleName FROM smbms_user u,smbms_role r
WHERE u.userRole= r.id
AND userName LIKE CONCAT('%',#{uName},'%')
AND u.userRole=#{uRole}
</select>
public List<User> getUserListByparam(@Param("uName") String userName,@Param("uRole") Integer userRole );
注意&&&&&&&
1 如果resultType没有写 会出现异常:
org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement 'cn.smbms.dao.user.UserMapper.getListByUserName'. It's likely that neither a Result Type nor a Result Map was specified.
2 #{userName}是叫做OGNL表达式
--------------第二个问题 为什么roleName 在User查询中没有显示?
答案:因为在多表查询的时候 查询的是smbms_role表中字段的 r.roleName这个字段
所有在映射的时候User类中的属性userRoleName没有赋值 所有null
解决方法一:
在类里面加上其他表的属性 然后sql语句加一个别名
在sql语句中加个别名 :
<select id="getUserListByparam" resultType="User" >(返回是User对象)
SELECT u.* ,r.roleName as userRoleName FROM smbms_user u,smbms_role r
WHERE u.userRole= r.id
AND userName LIKE CONCAT('%',#{uName},'%')
AND u.userRole=#{uRole}
</select>
解决方法二:
注意:
区别
resultType :直接表示返回类型
resultMap :对外部resultMap的引用
resultMap –用来描述数据库结果集和对象的对应关系
数据库字段信息与对象属性不一致
复杂的联合查询,自由控制映射结果 可以使用resultMap
resultMap自动映射匹配前提:字段名与属性名一致
可以使用resultMap处理 但是resultMap和resultType不可以共存
resultMap的自动映射级别-autoMappingBehavior
PARTIAL(默认):自动匹配所有
<!-- 使用resultMap改造 -->
<!-- 自定义结果映射 -->
<resultMap type="User" id="userList">
<result property="userRoleName" column="roleName"/>
</resultMap>
<!-- 根据用户名进行模糊查询 俩个参数 通过Map-->
<select id="getUserListByMap" resultMap="userList" >&&&&&(必须是resultMap)
SELECT u.* ,r.roleName FROM smbms_user u,smbms_role r
WHERE u.userRole= r.id
AND userName LIKE CONCAT('%',#{uName},'%')
AND u.userRole=#{uRole}
</select>
select中的resultMap是引用自定义结果映射器resultMap中的id保持一致
如果xml文件中加入了禁止了自动匹配 那么只能通过自定义的resultMap来从数据库中获取字段列
<settings>
<!-- lazyLoadingEnabled属性是延迟加载 -->
<setting name="lazyLoadingEnabled" value="false" />
<!-- 禁止自动匹配 默认自动匹配 NONE是禁止自动匹配-->
<setting name="autoMappingBehavior" value="NONE" />
</settings>
可以修改
<resultMap type="User" id="userList">
<result property="userRoleName" column="roleName" />
<result property="id" column="id" />
<result property="userCode" column="userCode" />
</resultMap>
这样就可以拿到这几个字段的值
----配置智能提示
点wiodow--xml catalog---add--file System --key(填写命名空间就行)
-----------------------insert 在使用中 要注意事务的自动和手动问题-------(没有resultMap)--------------------
注意点:
对于增删改 这些数据操作 需要注意俩点
1 默认返回的是受影响的行数 Dao层中的方法返回值类型一般为 int
2 都没有resultType也没有resultMap (二者都是Map数据结构)
3 (1)如果在获得sqlsession的时候设置了手动提交事务 factory.openSession(false);
那么在插入数据的时候 就要手动打开提交方式
(2)如果自动 提交事务 在serviceimpl中就不用再关闭事务了 factory.openSession(true);
--UserMapper.xml配置文件
<insert id="add" parameterType="User">
insert into smbms_user
(userCode,userName,userPassword,
userRole,gender,birthday,phone,address,creationDate,createdBy)
values(#{userCode},#{userName},#{userPassword},#{userRole},#{gender},#{birthday},#{phone},#{address},#{creationDate},#{createdBy})
</insert>
--UserServiceImpl
public boolean add(User user) {
boolean flag = false;
SqlSession session = null;
int row = 0;
try {
// 读取配置文件为流 创建实例把流读取返回一个sqlsessionfactory
session = MyBatisUtil2.getSqlSession();
row = session.getMapper(UserMapper.class).add(user);
session.commit();//在MyBatisUtil2设置手动提交了事务 所以要手动开启
if (row > 0) {
flag = true;
}
} catch (Exception e) {
if(session!=null){
session.rollback();
}
row = 0;
e.printStackTrace();
}finally{
MyBatisUtil2.closeSqlsession(session);
}
return flag;
}
----------------------4月26号知识点-----------修改删除的操作------------------
注意问题1: 如果#{ }里面没有写入参数 就会报BuilderException
<!-- 修改用户信息 -->
<update id="updateUser">
UPDATE smbms_user SET userName=#{userName},
gender=#{gender},phone=#{phone} -----&&&注意此处没有逗号
WHERE id = 28
</update>
dao层接口--public int updateUser(User user);
<!-- 修改用户密码 -->
<update id="updateUserPass">
UPDATE smbms_user SET userPassword=#{upass}
WHERE userCode=#{uname}
</update>
dao层接口--public int updateUserPass(@Param("upass") String userpass,@Param("uname")String userName);
<!-- 删除用户 -->
<delete id="delUser">
DELETE FROM smbms_user WHERE id=#{id}
</delete>
dao层接口--public int delUser(Integer id);
----service 大同小异 只写一个参考
public boolean delUser(Integer id) {
boolean flag = false;
SqlSession session = null;
int row = 0;
try {
// 读取配置文件为流 创建实例把流读取返回一个sqlsessionfactory
session = MyBatisUtil2.getSqlSession();
row = session.getMapper(UserMapper.class).delUser(id);
if (row > 0) {
session.commit();//在MyBatisUtil2设置手动提交了事务 所以要手动开启
flag = true;
}
} catch (Exception e) {
if(session!=null){
session.rollback();
}
row = 0;
e.printStackTrace();
}finally{
MyBatisUtil2.closeSqlsession(session);
}
return flag;
}
-----------------------深入学习resultMap------------------------
resultMap自动映射(autoMappingBehavior)的三个匹配级别
NONE
禁止自动匹配
PARTIAL(默认)
自动匹配所有属性,内部嵌套除外
FULL
自动匹配所有
通过设置<settings>可以设置resultMap自动映射的级别
如果有内部嵌套可以修改为 FULL
<settings>
<!-- lazyLoadingEnabled属性是延迟加载 -->
<setting name="lazyLoadingEnabled" value="false" />
<!-- 自动匹配所有 -->
<setting name="autoMappingBehavior" value="FULL" />
</settings>
--------------问题1
如果一个User类里面包含另外一个类Role 是User的属性 那怎么拿到Role里面的属性呢
答案 就要使用到内部嵌套了
方法1:把自动映射修改为FULL
<settings>
<!-- lazyLoadingEnabled属性是延迟加载 -->
<setting name="lazyLoadingEnabled" value="false" />
<!-- 自动匹配所有 -->
<setting name="autoMappingBehavior" value="FULL" />
</settings>
方法2:
不建议方法1 的使用
第一步:
使用association标签 一对一
property:映射数据库列的实体对象的属性
column:数据库列名或者别名
javaType="Role" 是role的java类型
(1)编写自定义映射resultMap
<!-- 自定义结果映射 -->
<resultMap type="User" id="userListByRole">
<result property="id" column="id" />
<result property="userCode" column="userCode" />
<result property="userName" column="userName" />
<result property="phone" column="phone" />
<!--javaType="Role" 是role的java类型 -->
<association property="role" javaType="Role">
<result property="id" column="r_id" />
<result property="roleName" column="roleName" />
</association>
</resultMap>
<!--查询角色编号对应的用户列表 -->
<select id="getUserListByRoleId" resultMap="userListByRole">
SELECT u.*,r.id as
r_id,r.roleName
FROM smbms_user u,smbms_role r
WHERE
u.userRole= r.id
AND r.id=#{roleId}
</select>
第三步:测试
注意要想拿到roleName必须是user.getRole.getRoleName
因为Role是User的属性所以先user.getRole.在getRoleName
------问题2 一个User用户对应多个联系人地址 获取指定的用户信息及其地址列表
可以使用collection 一对多
第一步:创建address,User实体类
在User类里面加属性
private List<Address> list; 并且set下
第二步:
创建接口
public List<User> getAddressListByUserId(Integer userId);
第三步:
collection里面的属性
property="list"对应的是User类里面的属性
ofType="Address"对应的是User类List里面的类
修改Usermapper.xml
(1)因为存在内部嵌套所有先自定义ResultMap
<!-- 自定义结果映射 -->
<resultMap type="User" id="UserAddressList">
<result property="id" column="id" />
<result property="userCode" column="userCode" />
<result property="userName" column="userName" />
<result property="phone" column="phone" />
property="list"对应的是User类里面的属性
ofType="Address"对应的是User类List里面的类
<collection property="list" ofType="Address">
<result property="id" column="a_id"/>
<result property="contact" column="contact"/>
<result property="addressDesc" column="addressDesc"/>
</collection>
</resultMap>
(2)sql语句
<!-- 查询指定的用户信息及其地址列表 -->
<select id="getAddressListByUserId" resultMap="UserAddressList">
SELECT u.*,a.id as
a_id,a.contact,a.addressDesc
FROM smbms_user u,smbms_address a
WHERE
u.id= a.userId
AND u.id=#{userId}
</select>
第四步 UserService
public List<User> findAddressListByUserId(Integer userId) {
List<User> list = new ArrayList<User>();
SqlSession session = null;
try {
// 读取配置文件为流 创建实例把流读取返回一个sqlsessionfactory
session = MyBatisUtil2.getSqlSession();
list = session.getMapper(UserMapper.class).getAddressListByUserId(userId);
} catch (Exception e) {
e.printStackTrace();
} finally {
MyBatisUtil2.closeSqlsession(session);
}
return list;
}
&&&&&第五步:测试
public static void main(String[] args) {
UserService us = new UserServiceImpl();
List<User> list=us.findAddressListByUserId(1);
for (User user : list) {
System.out.println(user.getUserName()+"的联系人地址:");
List<Address> alist=user.getList();
for (Address address : alist) {
System.out.println("联系人:"+address.getContact()+" \n地址: "+address.getAddressDesc());
}
}
}
注意resultMap里面关系对应好
-----------------------------------4月27号 动态sql语句---------------------------
<result property="userRoleName" column="roleName" />
property是实体类的属性 column是数据库的字段或者别名
用于实现动态SQL的元素主要有
if
trim
where
set
choose(when、otherwise)
foreach
mybatis功能强大基于OGNL的表达式
1 简单的if ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
注意: 使用中没有&&是用and连接
<select id="getUserListByUserNameAndRole" resultType="User">
SELECT u.*
,r.roleName FROM smbms_user u,smbms_role r
WHERE
u.userRole=r.id
<if test="userName!=null and userName!='' ">
AND userName LIKE CONCAT('%',#{userName},'%')
</if>
<if test="userRole!=null and userRole>0">
AND u.userRole=#{userRole}
</if>
</select>
2 where 的使用 ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
---之前是这样处理and和or
<select id="getUserListByMap" resultMap="userList">
SELECT * FROM smbms_user WHERE 1=1
<if test="userName!=null and userName!='' ">
AND userName LIKE CONCAT('%',#{userName},'%')
</if>
<if test="userRole!=null and userRole>0">
AND userRole=#{userRole}
</if>
</select>
----mybatis使用
<select id="getUserListByMap" resultMap="userList">
SELECT * FROM smbms_user
<where>
<if test="userName!=null and userName!='' ">
AND userName LIKE CONCAT('%',#{userName},'%')
</if>
<if test="userRole!=null and userRole>0">
AND userRole=#{userRole}
</if>
</where>
</select>
3 set+if只能解决更新问题 update ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
---以前
UPDATE smbms_user SET userName=#{userName}, gender=#{gender},phone=#{phone}
WHERE id = #{id}
---mybatis
UPDATE smbms_user
<set>
<if test="userName!=null">userName=#{userName},</if>
<if test="gender!=null">gender=#{gender},</if>
<if test="phone!=null">phone=#{phone}</if>
</set>
WHERE id = #{id}
注意:::在使用的时候注意逗号别忘记加
第一个坏处会破坏原来的数据 不设置就把原来的电话号码设置为null 所以使用动态sql
4 trim 更灵活地去除多余关键字 ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
使用if+trim 可以替代 where+if
使用if+trim 可以替代 set+if
属性
prefix
suffix
prefixOverride
s
suffixOverrides
代替 if+where
SELECT * FROM smbms_user
<trim prefix="WHERE" prefixOverrides="AND|OR">
<if test="userName!=null and userName!='' ">
AND userName LIKE CONCAT('%',#{userName},'%')
</if>
<if test="userRole!=null and userRole>0">
AND userRole=#{userRole}
</if>
</trim>
代替 if+set
UPDATE smbms_user
<trim prefix="SET" suffixOverrides=",">
<if test="userName!=null and userName!=''">userName=#{userName},</if>
<if test="gender!=null">gender=#{gender},</if>
<if test="phone!=null and phone!=''">phone=#{phone}</if>
</trim>
WHERE id = #{id}
5 foreach ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
迭代一个集合,通常用于in条件
属性
item
index
collection:必须指定
list
array
map-key
open
separator
close
需求 查询用户角色编号为2 或者3 的用户列表
sql=SELECT * FROM smbms_user WHERE userRole IN (2,3)
<select id="getUserListByUserRole" resultType="User">
SELECT * FROM smbms_user
WHERE userRole IN
<foreach item="integer" collection="array" open="(" separator="," close=")" >
#{integer}
</foreach>
</select>
其中 item="integer" 代表的是参数的名字
collection=array 代表参数的类型是数组 (如果是集合就写list )
open="(" 代表IN后面以(开头
separator="," 代表参数中间以逗号隔开
close=")" 代表IN后面以(开头
需求2 按性别 角色编号为 2 3 的用户列表
<select id="getUserListBy_foreach_map" resultType="User">
SELECT * FROM smbms_user
WHERE gender=#{gender} AND
userRole IN
<foreach item="list" collection="list" open="("
separator="," close=")">
#{list}
</foreach>
</select>
item 数组的名字
#{list} 是要遍历的数组
collection是Map的key值
------test
UserService us = new UserServiceImpl();
Map<String, Object> map=new HashMap<String, Object>();
List<Integer> list=new ArrayList<Integer>();
list.add(2);
list.add(3);
map.put("list", list);
map.put("gender", 2);
List<User> ulist=us. getUserListBy_foreach_map(map);
for (User user : ulist) {
System.out.println(user.getUserName());
}
6 分页
<!-- 分页查询 -->
<select id="getUserListPage" resultType="User">
SELECT u.*
,r.roleName FROM smbms_user u,smbms_role r
WHERE
u.userRole=r.id
<if test="userName!=null and userName!='' ">
AND userName LIKE CONCAT('%',#{userName},'%')
</if>
<if test="userRole!=null and userRole>0">
AND u.userRole=#{userRole}
</if>
ORDER BY creationDate desc
LIMIT #{from} ,#{pageSize}
</select>
-------------------------------4月28号 ------------------项目整合Spring+SpringMVC+Mybatis
1 存储过程和触发器 ************非常重要
2 前端框架 :JQuery vue Bootstrap(响应式布局 前后端分离) React
3问题: 自己写的Controller都对 gologin.do也都对 但是总是报 noMaopper说明扫描包的时候没有扫描到 看配置文件
整合步骤
第一步:导包
第二步:配置web.xml
第三步:配置文件
applicationContext-mybatis.xml
database.properties
mybatis-config.xml
log4j.properties
springmvc-servlet.xml
第四步:
数据对象模型(cn.smbms.pojo)
DAO数据访问接口(cn.smbms.dao)
系统服务接口(cn.smbms.service)
前端控制层Controller(cn.smbms.controller)
系统工具类(cn.smbms.tools)
前端页面(/WEB-INF/jsp)
静态资源文件(/WebRoot/statics)
心跳包:
在校验连接的同时,解决数据库重新连接的问题,从而确保连接池中连接是真实有效的连接
-------------------------5月2号知识点----------SL会员系统问题-------------------------
第一个:
@InitBinder用于在@Controller中标注于方法,
表示为当前控制器注册一个属性编辑器或者其他,只对当前的Controller有效。
在需要日期转换的Controller中
使用SpringMVC的注解@initbinder和Spring自带的WebDateBinder类来操作。
@InitBinder和WebDataBinder一起使用解决String--》Date
第二个:
Spring中的@scope注解
@controller默认单列模式如果加上@Scope("prototype") 代表原型(多列)
第三个:
ModelAndView:
SpringMvc的ModelAndView中的model就是一个Map
如果您要返回Model对象,则可以使用Map来收集这些Model对象,然后设定给ModelAndView,
ModelAndView(String viewName, Map model)
列如:
return new ModelAndView("main",model); mian是view model是一个map集合
第四个:
svn的使用:已保存sogou浏览器上
svn(subversion)=版本控制+备份服务器
客户端
把svn包放在myeclipse的dropins下面就行了
window--show view--svn资源库 --新建
项目--右键点击tream--sharproject--使用已有的创建资源库
项目--右键点击tream--分支-
第五个:
-------------------Bootstrap(charisma-master)---------的使用
简单灵活可用于框架流行的用户界面和交互接口的html、css、JavaScript工具集
基于jQuery框架,并兼容大部分jQuery插件
基于html5、css3实现响应式设计(手机电脑自动调节分辨率)
由于很多组件都是通过jQuery插件扩展出来的,故须拷贝html原生代码
第六个:
-------------------Redis----------的使用
非关系型数据缓存数据库
本质上是一个高性能的key-value数据库
常用命令:
set key value
设置key对应的值为string类型的value,返回1表示成功,0表示失败
get key
获取key对应的string值,若key不存在返回null
exists key
判断指定key是否存在,返回1表示存在,0表示不存在
Redis代码实现靠JedisPool引用(jedisPool.getResource();---得到jedis jedis.set( key, value))set get exists 方法
第七个:
系统架构目标
可靠性 安全性 可扩展性 可定制化 可维护性 用户体验 市场时机
第八个:
toggle() 方法切换元素的可见状态。
如果被选元素可见,则隐藏这些元素,如果被选元素隐藏,则显示这些元素。
第九个:
attr()
在JS中设置节点的属性与属性值用到setAttribute(),获得节点的属性与属性值用到getAttribute(),
而在jquery中,用一个attr()就可以全部搞定了
jquery中用attr()方法来获取和设置元素属性,attr是attribute(属性)的缩写
第十个:
ajax中把表单中的元素封装成一个对象 然后传递到ajax
ajax中的url是把请求发送到服务器那个地址上
function addUser(){
var user = {
uname:$("#uname").val(),
mobileIpt:$("#mobileIpt").val(),
birthday:$("#birthday").val()
};
$.ajax({
url:'UserAdd.action',
data:user,
type:'post',
dataType:'text',
success:function(msg){
if(msg=='1'){
console.log('添加成功');
}else{
console.log('添加失败')
}
}
})
}
后台参数直接拿一个user就行了
-------------------ajax中面向对象的传递参数方式---------简单但是慎用
-------js中
&&&&& user:JSON.stringify(user)
JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串
User----String
$("#loginBtn").click(function(){
var user = new Object();
user.loginCode = $.trim($("#logincode").val());
user.password = $.trim($("#password").val());
user.isStart = 1;
if(user.loginCode == "" || user.loginCode == null){
$("#logincode").focus();
$("#formtip").css("color","red");
$("#formtip").html("对不起,登录账号不能为空。");
}else if(user.password == "" || user.password == null){
$("#password").focus();
$("#formtip").css("color","red");
$("#formtip").html("对不起,登录密码不能为空。");
}else{
$("#formtip").html("");
$.ajax({
url: 'login.html',
type: 'POST',
data:{user:JSON.stringify(user)},
dataType: 'html',
timeout: 1000,
error: function(){
$("#formtip").css("color","red");
$("#formtip").html("出现错误,登录失败!请重试。");
},
success: function(result){
if(result != "" && "success" == result){
window.location.href='main.html';
}else if("failed" == result){
$("#formtip").css("color","red");
$("#formtip").html("登录失败!请重试。");
$("#logincode").val('');
$("#password").val('');
}
else if("nologincode" == $.trim(result)){
$("#formtip").css("color","red");
$("#formtip").html("登录账号不存在,请重试。");
}else if("nodata" == result){
$("#formtip").css("color","red");
$("#formtip").html("对不起,没有任何数据需要处理!请重试。");
}else if("pwderror" == result){
$("#formtip").css("color","red");
$("#formtip").html("登录密码错误,请重试。");
}
}
});
}
});
--------controller
&&&&&注意是将ajax传递过来的user对象转换为一个java中的user对象
JSONObject userObject = JSONObject.fromObject(user);
java代码转换成json
User userObj = (User)JSONObject.toBean(userObject, User.class);
从JSONObject 对象转换为 JAVA 对象
@RequestMapping("/login.html")
@ResponseBody
public Object login(HttpSession session,@RequestParam String user){
if(null == user || "".equals(user)){
return "nodata";
}else{
JSONObject userObject = JSONObject.fromObject(user);
User userObj = (User)JSONObject.toBean(userObject, User.class);
try {
if(userService.loginCodeIsExit(userObj) == 0){//不存在这个登陆账号
return "nologincode";
}else{
User _user = userService.getLoginUser(userObj);
if(null != _user){
session.setAttribute(Constants.SESSION_USER, _user);
User updateLoginTimeUser = new User();
updateLoginTimeUser.setId(_user.getId());
updateLoginTimeUser.setLastLoginTime(new Date());
userService.modifyUser(updateLoginTimeUser);
updateLoginTimeUser = null;
return "success";
}else {
return "pwderror";
}
}
} catch (Exception e) {
return "failed";
}
}
}
第十一个:
因为分页用户 商品 都可能用得到 所以可以把分页用到的总页数 当前页 用户列表封装在一个对象里面
然后在controller里面给他赋值
第十二个:
disabled 属性规定应该禁用 input 元素。 被禁用的 input 元素既不可用,也不可点击。
第十三个:
在view中--格式化--User对象的时间类型显示
<fmt:formatDate value="${user.createTime}" pattern="yyyy-MM-dd"/>
a标签中的title属性
放到标签的文字上,会悬浮展示title属性的值。
得到主菜单
#主菜单(根据角色找到对应的功能)
SELECT * FROM au_function
WHERE id IN (
SELECT functionId FROM au_authority WHERE roleId=1
)
AND parentId=0
#得到子菜单
SELECT * FROM au_function
WHERE id IN (
SELECT functionId FROM au_authority WHERE roleId=1
)
AND parentId=1;