框架:已经封装好的类以及规则内容(如何和数据库链接交互,页面之间的值的传递),可以使用已经封装好的类,只会考虑业务逻辑问题以简化开发
SSM:Spring, SpringMVC,Mybatis整合使用
MVC:浏览器向用户展示页面(html(JSP):view),Servlet与view进行数据驱动(Control决定展示什么样的view),并接受用户的输入(control),Model和Control进行数据交互(model层里面有业务逻辑和数据操作的内容),Model和database进行数据操作
Spring: 项目中的装配bean对象的工厂不需要程序员显示的创建对象,核心使用IOC技术(控制反转,依赖注入:抵消耦合度)
SpringMVC:利用拦截器拦截用户的请求并进行分析,然后寻找对应的controller
Mybatis:永久层框架(数据访问层)JDBC的一个封装操作(程序员只需要注意SQL语句)
MyBatis支持普通的SQL查询,存储过程,几乎消除了JDBC代码和参数的设置(需要下载框架的JAR:Mybatis-connector-java.jar,mybatis.jar),不需要自己在创建Connection,statement的创建,也不需要对查询结果一条一条查询,并组装对象
MyBatis使用XML或者注解来配置以及原始映射将JAVA对象映射成数据库当中的记录
Mybatis的XML配置文件当中包含了一系列影响Mybatis的属性信息
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/test/UserMapper.xml">mapper>
mappers>
configuration>
可以利用properties进行设置变量的值,properties节点将会被放在configuration节点中,用于提供数据库参数数据
<properties resource="org/mybatis/example/config.properties">
properties>
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/webproject?characterEncoding=utf-8&serverTimezone=GMT
username=root
password=123456
mapper映射:用于告诉mybatis将数据表中的记录封装成什么样的对象
需要创建映射类,映射于数据表
本质上仍旧是XML文件放置SQL语句,以及告诉mybatis什么是映射类(每一张数据表往往都会有自己的映射文件)[以表名+Mapper明明的XML文件]
<mapper namespace="com.test.UserMapper">
<select id="selectEmail" resultType="com.test.User">
select * from webUser
select>
mapper>
SqlSessionFactory对象:用于创建SqlSession对象
SqlSessionFactoryBuilder:用于创建SqlSessionFactory对象
均在配置XML文件当中进行创建,放在DAO(数据处理层)
用于调用在mapper文件当中已经写好了的SQL语句,底层已经封装了JDBC的操作
看似创建的对象很多,其实在利用Spring框架进行整合之后不会那么的复杂
package com.dao;
import com.test.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
import java.util.List;
public class UserDao {
//这个方法用于查询所有的用户信息
public List<User> selectUser(){
//1. 创建SqlSessionFactoryBuilder
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("mybatis.xml");
//读取xml配置信息(包括数据库的信息)
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//2. 创建SqlSessionFactory
SqlSessionFactory factory = builder.build(inputStream);
//创建了一个针对一个数据库的factory
//3. 创建SqlSession
SqlSession sqlSession = factory.openSession();
List<User> list = sqlSession.selectList("com.test.UserMapper.selectEmail");
//sqlsession当中封装了大量的sql的操作,比如selectList就是直接返回结果集,里面的参数指的是sql语句可能需要的参数
sqlSession.close();
return list;
}
}
<select id="selectUserByEmail" resultType="com.test.User" parameterType="String">
select * FROM user where email=#{email}
select>
public User selectUserByEmail(String email){
SqlSession sqlSession = UserDao.getFactory().openSession();
User user = sqlSession.selectOne("com.test.UserMapper.selectUserByEmail", email);
//第一个参数是SQL储存的节点位置,后面的参数是传入SQL的参数
return user;
}
<select id="selectUserByEmailAndPassword" resultType="com.test.User" parameterType="com.test.User">
select * FROM user where email=#{email} and password=#{password}
select>
传入的参数就可以创建一个参数类,包含了需要的参数(SQL中的占位符只需要写出类中的成员属性就可以了)
public User selectUserByEmailAndPassword(){
SqlSession sqlSession = UserDao.getFactory().openSession();
User user = new User("[email protected]","123","eric");
User user1 = sqlSession.selectOne("com.test.UserMapper.selectUserByEmail", user);
return user1;
}
用于简化XML用引用类而写的全类名
<typeAliases>
<typeAlias type="com.test.User" alias="User"/>
typeAliases>
<typeAliases>
<package name="com.test"/>
typeAliases>
使用package标签,就可以在mapper文件当中省略掉所有该包名
在配置文件当中注册mapper时不能省略报名,那个是路径使用/
<settings>
<setting name="logImpl" value=" STDOUT_LOGGING"/>
settings>
使用insert标签,大致使用方式和select标签差不了太多
<insert id="insertIntoUser" parameterType="User">
insert into user values(#{email},#{password},#{Username})
insert>
public void addUser(User user){
SqlSession sqlSession = UserDao.getFactory().openSession();
sqlSession.insert("insertIntoUser", user);
sqlSession.commit(); //对于insert和update类型的修改需要commit也就是提交
sqlSession.close();
}
<update id="updateUserByEmail" parameterType="User">
update user set email=#{email},username=#{username},password=#{password} where email=#{email}
update>
<delete id="deleteByEmail" parameterType="String">
delete from user where email=#{email}
delete>
public void updateByEmail(User user){
SqlSession sqlSession = UserDao.getFactory().openSession();
sqlSession.update("updateUserByEmail", user);
sqlSession.commit();
sqlSession.close();
}
public void deleteByEmail(String email){
SqlSession sqlSession = UserDao.getFactory().openSession();
sqlSession.delete("deleteByEmail", email);
sqlSession.commit();
}
利用标签实现动态查询:if,choose,trim,foreach
<select id="selectUserByParameter" parameterType="User">
select * from user
<where>
<if test="email!=null">
email=#{email}
if>
<if test="password!=null">
and password=#{password}
if>
where>
select>
和Java中的switch,case,default作用几乎相同,只能选择一个条件
<select id="selectUserByParameter1" parameterType="User" resultType="User">
select * from user
<where>
<choose>
<when test="email!=null">
email=#{email}
when>
<when test="password!=null">
password=#{password}
when>
<otherwise>
otherwise>
choose>
where>
select>
假设有多个条件同时成立,只会进入第一个条件
用于更新数据,解决update只能更新固定字段的问题,使用在update标签之中
<update id="updateUserUsingSet" parameterType="User">
update user
<set>
<if test="password!=null">password=#{password},if>
<if test="usernameS!=null">username=#{username}if>
set>
where email=#{email}
update>
循环遍历:比如批量删除,批量添加之类的
<select id="selectPostIn" resultType="User">
select * from user where email in
<foreach collection="list" item="item" index="index" open="(" separator="," close=")">
#{item}
foreach>
select>
select * from user like '%e%';
like的用法:用于模糊搜索:表示包含的意思,在字符串当中需要将字符用%包含
<select id="selectLike" resultType="User" parameterType="String">
select * from user where username like "%"#{keyword}"%"
select>
Java map:相当于是键值对:一个名字对应一个对象或者是集合(可以用于多种参数(包含集合)的传入:使得mybatis通过字符串引用变量
//给map中添加元素
Map<String, String> map = new HashMap<String,String>();
map.put("邓超", "孙俪");
map.put("李晨", "范冰冰");
map.put("刘德华", "柳岩");
综合查询(往往传入的参数是map类型的参数)
<select id="selectTogether" parameterType="Map" resultType="User">
select * from user where username in
<foreach collection="list" item="item" index="index" open="(" separator="," close=")">
#{item}
foreach>
and username like "%"#{keyword}"%"
select>
public List<User> selectTogether(){
Map<String,Object> map = new HashMap<>();
ArrayList<String> list = new ArrayList<>();
list.add("eric");
list.add("jinkens");
map.put("list", list);
map.put("keyword", "e");
SqlSession sqlSession = UserDao.getFactory().openSession();
return sqlSession.selectList("selectTogether", map);
}
<resultMap id="User_CVE" type="User">
<id property="username" column="username"/>
<result property="email" column="email"/>
<result property="password" column="password"/>
<association property="cve" javaType="CVE">
<id property="cve_id" column="vul_id"/>
<result property="category" column="vul_category"/>
<result property="desc" column="description"/>
association>
resultMap>
public class User {
private String email;
private String password;
private String username;
private CVE cve;
}
public class CVE {
private String cve_id;
private String category;
private String desc;
}
第二种查询方式
<select id="selectCveUser2" resultMap="User_cve2">
select email,cve_id from user_cve
select>
<select id="selectCVEbyCveid" parameterType="String" resultMap="CVE">
select * from text_data1 where vul_id=#{cve_id}
select>
<resultMap id="CVE" type="CVE">
<id property="cve_id" column="vul_id"/>
<result property="desc" column="description"/>
<result property="category" column="vul_category"/>
resultMap>
<resultMap id="User_cve2" type="User">
<result property="email" column="email"/>
<association property="cve" column="cve_id" select="selectCVEbyCveid" javaType="CVE">
<id property="cve_id" column="vul_id"/>
<result property="category" column="vul_category"/>
<result property="desc" column="description"/>
association>
resultMap>
假设类成员属性的名称和字段名称不同则也必须用resultMap,不能直接用resultType
一般在DAO层需要调用mapper文件当中的SQL语句时,需要自己复制上命名空间(namespace)以及SQL的id
//动态代理对应的接口
public interface UserMapper {
public List<User> selectUser();
public User selectUserByEmail(String email);
}
public User selectUserByEmail(String email){
SqlSession sqlSession = UserDao.getFactory().openSession();
//创建动态代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //会自动将接口实现并创建一个对象
User user = userMapper.selectUserByEmail(email);
sqlSession.close();
return user;
}
resultMap当中association和collection标签具有延迟加载的功能,因为不一定这条查询语句就会被使用,在关联查询时回先加载著信息,使用关联信息的时候再加载关联信息(只适用于嵌套查询)
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
maven就是套在web项目外层,并且使用pom.xml文件来帮助导入jar包的工具
检索的顺序:本地仓库-远程仓库-中央仓库
通过settings.xml 更改本地仓库localRepository
<localRepository>E:\maven\repositorylocalRepository>
<mirrors>
<mirror>
<id>nexus-aliyunid>
<mirrorOf>centralmirrorOf>
<name>Nexus aliyunname>
<url>http://maven.aliyun.com/nexus/content/groups/publicurl>
mirror>
mirrors>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.13version>
dependency>
依赖的信息可以从maven中央仓库进行获取
groupId:是项目组织唯一的标识符,实际对应JAVA的包的结构,是main目录里java的目录结构
artifactId:就是项目的唯一的标识符,实际对应项目的名称,就是项目根目录的名称
version:版本号 后缀为release:代表稳定的版本
scope: 默认的依赖范围是compile
1、test范围指的是测试范围有效,在编译和打包时都不会使用这个依赖
2、compile范围指的是编译范围有效,在编译和打包时都会将依赖存储进去
3、provided依赖:在编译和测试的过程有效,最后生成war包时不会加入,诸如:servlet-api,因为servlet-api,tomcat等web服务器已经存在了,如果再打包会冲突
4、runtime在运行的时候依赖,在编译的时候不依赖
在pom.xml当中添加完依赖之后点击maven change即可自动导入
<resources>
<resource>
<directory>${basedir}/src/main/com/java/mapperdirectory>
<includes>
<include>**/*.xmlinclude>
<include>**/*.propertiesinclude>
includes>
resource>
resources>
所有配置文件全部放在和java文件夹同级的地方并设置为source boot
需要在pom.xml当中导入相应的依赖
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
web.xml当中的配置有问题:使用的webApp版本太低
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
web-app>
将此段xml配置信息取代原web.xml当中的代码
spring是一个非常活跃的开源框架。基于IOC和aop来构架多层javaEE系统,以帮助分离项目组件之间的依赖关系(根本目的:解除耦合度)
底层: 工厂模式+xml(可以用于帮助创建对象并注入到需要的地方)
耦合之处:在连接DAO和servlet(控制层)的service层(写对DAO层调用出来的数据的逻辑处理)当中往往需要创建DAO的对象(DAO的成员方法中封装着利用sqlsession调用SQL的语句)
方法:创建一个工厂类,将service中的创建对象语句固定,由工厂类语句决定创建什么类型的对象,再次由XML文件解除工厂类和DAO层的耦合度,工厂类将读取XML文件再根据xml文件决定创建对象的类型
xml中的bean标签:表示对象的意思(第一句话是创建一个DAO对象,第二句话是注入并赋值给stuDao属性)
<bean ID="myStuDao" class="com.test.dao.OracleStuDao"> <bean ID="stuService" class="com.test.service"> <property name="stuDao" ref="myStuDao"/> bean>
从而在service中只需要存在一个Dao的对象引用就可以,不需要创建对象
IOC (Inverse of Control) :控制反转(原来创建对象(DAO对象)的权利在service层当中,现在将这个权利剥夺,并交给工厂类(是降低对象之间的耦合关系的设计思想)
将service层中的new语句取消,只留下对象引用:过程是程序读取Spring配置文件,获取需要创建的bean对象
DI(Dependency injection):依赖注入(创建对象实例时,同时为这个对象注入它所依赖的属性)
<bean ID="stuService" class="com.test.service">
<property name="stuDao" ref="myStuDao"/>
bean>
总结:控制反转的实现方式就是依赖注入
Spring IOC:能够帮我们根据配置文件创建及组装对象之间的依赖关系
Spring AOP(面向切面编程):能够帮助我们无耦合的实现日志记录,性能统计,安全控制
在某一个层当中(比如DAO层)插入一条打印信息的语句(同样有Spring进行添加)
spring能够非常简单的帮我们管理数据库事务
spring提供了与第三方数据访问框架无缝连接,比如Hibernate,mybatis,而且自己也提供了一套jdbc模板来用来数据的访问
spring还提供了与第三方web框架的无缝连接,比如structs,并且自己也提供了一套springMVC框架,来方便web层搭建
spring能方便的与javaEE技术整合,比如Java mail,任务调度,还可以与其它技术整合,比如缓存.
spring-core:依赖注入IOC与DI的最基本实现
spring-beans:Bean工厂与bean的装配
spring-context:spring的context上下文即IOC容器
spring-context-support:Spring context的扩展支持,用于MVC方面
spring-expression:spring表达式语言
分别导入上述的Spring核心的jar包
Spring core
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>5.2.6.RELEASEversion>
dependency>
Spring Beans
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>5.2.6.RELEASEversion>
dependency>
Spring context
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.6.RELEASEversion>
dependency>
Spring context support
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
<version>5.2.6.RELEASEversion>
dependency>
Spring expression
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-expressionartifactId>
<version>5.2.6.RELEASEversion>
dependency>
<bean id="userCveDao_01" class="DAO.UserCveDao"/>
class属性是类的全类名
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");
UserCveDao userCveDao = applicationContext.getBean("userCveDao_01",UserCveDao.class);
这只是暂时用于测试的方法,DI能够直接注入到所需要的成员属性
UserCveDao userCveDao = applicationContext.getBean("userCveDao_01",UserCveDao.class);
scope:singletype和prototype:单例模式和多例模式:同一个bean在多次获取时获取的对象是否是同一个对象(设置对象的生成方式)
lazy-init:更改创建对象的时间:
lazy-init=“false” :默认值,不延迟创建,即在创建IOC容器的时候就创建对象
lazy-init=“true” :延迟初始化,在使用getBean的时候才会创建对象
初始化/销毁:init-method=“init” destroy-method=“destroy”(确定初始化以及销毁的方法)
生命周期中的构造函数之后其他方法之前调用
<bean id="drink_01" name="drink_02" scope="singleton"
lazy-init="true"
init-method="init" destroy-method="destroy"
class="com.test.pojo.Drink" />
<bean id="drink_01" class="com.test.pojo.Drink" />
利用有参数构造方法创建对象
public class SequenceFile {
private int dependency1;
private String dependency2;
public SequenceFile(int dependency1, String dependency2) {
this.dependency1 = dependency1;
this.dependency2 = dependency2;
}
}
<bean id="sequenceFile" class="com.market.SequenceFile">
<constructor-arg value="abc" index="1" type="String"/>
<constructor-arg value="123" index="0" type="int"/>
bean>
往往这种使用静态工厂创建对象的类都属于第三方jar包提供,比如SqlSessionFactory需要SqlSessionFactoryBuilder进行build
public class DrinkFactory2 {
public static Drink createDrink(){
return new Drink();
}
}
<bean id="drink_04" class="com.test.drinkFactory" factory-method="createDrink" />
public class DrinkFactory2 {
public Drink createDrink(){
return new Drink();
}
}
<bean id="drinkFactory" class="com.test.factory.DrinkFactory2" />
<bean id="drink_04" factory-bean="drinkFactory" factory-method="createDrink" />
在xml文件中 先创建工厂对象,再调用工厂中的方法来创建我们需要的对象
将创建的对象所依赖的属性进行注入
public class Drink {
private String name;
private String sugar;
private float price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSugar() {
return sugar;
}
public void setSugar(String sugar) {
this.sugar = sugar;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public Drink() {
System.out.println("创建一杯饮料");
}
}
<bean id="drink_01" class="com.test.pojo.Drink" >
<property name="name" value="西瓜汁" />
<property name="price" value="18" />
<property name="sugar" value="半糖" />
bean>
public class CVE {
private String cve_id;
private String category;
private String desc;
public CVE(String cve_id, String category, String desc) {
this.cve_id = cve_id;
this.category = category;
this.desc = desc;
}
public String getCve_id() {
return cve_id;
}
public String getCategory() {
return category;
}
public String getDesc() {
return desc;
}
public void setCve_id(String cve_id) {
this.cve_id = cve_id;
}
public void setCategory(String category) {
this.category = category;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
<bean id="CVE_01" class="test.CVE">
<constructor-arg index="0" value="CVE-1999-1431"/>
<constructor-arg index="1" value="设计错误"/>
<constructor-arg index="2" value="ZAK in Appstation mode allows users to bypass the Run only allowed apps policy by starting
Explorer from Office 97 applications (such as Word), installing software into the TEMP directory
, and changing the name to that for an allowed application, such as Winword.exe."/>
bean>
创建复杂对象:包含DAO类型成员属性的service对象的创建
public class UserCveService {
private UserCveDao dao;
public UserCveDao getDao() {
return dao;
}
public void setDao(UserCveDao dao) {
this.dao = dao;
}
public void test(){
List<User> list = dao.selectMoreTable2();
for (User user:list) {
user.tell();
}
}
}
<bean id="userCveDao_01" class="DAO.UserCveDao"/>
<bean id="userCveService_01" class="service.UserCveService">
<property name="dao" ref="userCveDao_01"/>
bean>
引入P空间
xmlns:p=“http://www.springframework.org/schema/p”
将这句语句加在beans节点下的属性当中:
<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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> beans>
使用P空间注入
<bean id="CVE_p" class="test.CVE"
p:category="设计错误"
p:cve_id="CVE-1999-1431"
p:desc="ZAK in Appstation mode allows users to bypass the Run only allowed apps policy by starting.Explorer from Office 97 applications (such as Word), installing software into the TEMP directory, and changing the name to that for an allowed application, such as Winword.exe."/>
<bean id="userCveDao_01" class="DAO.UserCveDao"/>
<bean id="userCveService_01" class="service.UserCveService" p:dao-ref="userCveDao_01"/>
public class TestBean_01 {
private int[] array;
private User[] arrayUser;
private List<String> stringList;
private Properties properties;
private Map<String, User> map;
}
<bean id="testBean" class="test.TestBean_01">
<property name="array">
<array>
<value type="int">1value>
<value type="int">2value>
array>
property>
<property name="arrayUser">
<array>
<ref bean="user_02"/>
array>
property>
<property name="stringList">
<list>
<value type="java.lang.String">tomvalue>
<value type="java.lang.String">jackvalue>
list>
property>
<property name="map">
<map>
<entry key="first" value-ref="user_02"/>
map>
property>
<property name="properties">
<props>
<prop key="driver">com.mysql.jdbc.Driverprop>
<prop key="url">jdbc:mysql://localhost:3306/webproject?characterEncoding=utf-8&serverTimezone=GMTprop>
<prop key="username">rootprop>
<prop key="password">123456prop>
props>
property>
bean>
Spring expression language:注入的值不再是上述的固定值:比如从DAO层传入
Spel产生的都是对象,不会产生方法
比如如果只是引入对象中的某个属性 可以 用#{}
<bean id="outSeller_05" class="com.test.pojo.OutSeller" p:type="饿了么"
p:drink-ref="drink_05" />
<bean id="outSeller_06" class="com.test.pojo.OutSeller">
<property name="type" value="#{outSeller_05.type}" />
<property name="drink" ref="drink_05" />
bean>
<bean id="user_02" class="test.User">
<constructor-arg index="0" value=""/>
<constructor-arg index="1" value=""/>
bean>
<bean id="testSpel_02" class="test.TestSpel">
<constructor-arg index="0" ref="user_02"/>
bean>
<bean id="testSpel_01" class="test.TestSpel_01">
<property name="user" value="#{testSpel_02.getNormalUser()}"/>
bean>
<bean id="testSpel_03" class="test.TestSpel_01">
<property name="user" value="#{T(test.TestSpel).getStaticUser()}"/>
bean>
访问成员属性: #{对象.属性名}
访问静态方法: #{T(包名.类名).方法名([参数])}
访问成员方法: #{对象.方法名()}
案例目的:创建userCveService和userCveDao对象,并将dao对象注入到service对象当中
注解只能用在自己写的实用类,并不能用在导入的类,因为注解都是写在类的源代码上方的
注解信息写在Spring框架的配置文件当中,需要指定撰写注解的类的包名,会全部进行扫描
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<context:component-scan base-package="com.test" />
beans>
<context:component-scan base-package="com.test" />
表明的是使用了注解ioc方式的包(context写在beans节点之下)
//创建一个对象(组件)
@Component
//创建service层对象,没有什么特殊的含义的对象,比如DAO对象
@Service
//创建控制层对象
@Controller
//默认会创建一个DrinkService的对象 对象的名字为drinkService (类名的首字母小写)
@Service
//也可以设置自己制定的对象名
@Service("myDrinkService")
public class DrinkService implements IDrinkService {
}
创建对象的注解写的位置就是这个类的声明处
注解方式注入可以不需要get,set方法,但是配置文件的方式需要
依赖注入的注解同样是写在创建对象的类的声明处
依赖注入之前,这些对象都需要被创建
//根据类型自动注入
@Autowired
//如果满足自动注入的对象有多个,可以通过@Qualifier()设置具体的对象名
@Qualifier("对象名")
//根据对象名注入,作用相当于@Autowired+@Qualifier("对象名")
@Resource(name="对象名")
//自动注入
@Autowired
//指定注入的对象(如果满足注入对象有多个的时候)
@Qualifier("oracleDrinkDao")
private IDrinkDao drinkDao;
public IDrinkDao getDrinkDao() {
return drinkDao;
}
//也可以在set方法上设置自动注入,也可以不需要set方法
public void setDrinkDao(IDrinkDao drinkDao) {
this.drinkDao = drinkDao;
}
@Resource(name="oracleDrinkDao")
//相当于autowired+qualifier
private IDrinkDao drinkDao;
public IDrinkDao getDrinkDao() {
return drinkDao;
}
public void setDrinkDao(IDrinkDao drinkDao) {
this.drinkDao = drinkDao;
}
创建对象需要注入普通类型:String:使用@Value标签
@Component
public class User {
@Value("[email protected]")
private String email;
@Value("123456")
private String password;
@Value("eric")
private String username;
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
public String getUsername() {
return username;
}
public void setEmail(String email) {
this.email = email;
}
public void setPassword(String password) {
this.password = password;
}
public void setUsername(String username) {
this.username = username;
}
}
设置为多例模式:@Scope(指的是利用工具包获取bean时候获取的是否是同一对象
设置对象的作用域,默认是单例,可以设置为多例模式@Scope(scopeName=“prototype”)
设置是否懒加载:@Lazy
默认是非懒加载,设置 @Lazy代表懒加载,前提是单例模式
//@Scope(scopeName ="prototype" )
//设置是否是懒加载 默认是false 前提是单例
@Lazy
@Component
public class Drink {
@Value("橙汁")
private String name;
}
AOP(Aspect Oriented program):面向切面编程
基本开发方式(由一名程序员开发一个模块的control,service和DAO层,一个纵向的过程)
问题:假设需要在service层需要添加一个权限判断,则需要在所有的service进行更改
AOP:将需要修改的代码写在外面,然后通过切面切入一个层当中(相当于对某一个层的所有模块进行了一个统一的修改)
AOP应用点(并不影响原来的业务结构):权限认证、日志、事务
核心关注点
纵向的业务流程,每一个模块之间都不相同
横切关注点
与业务逻辑关系不大,发生在核心关注点的多处出现,各处基本相似,AOP就是将横切关注点利用“横切”的技术剖解并封装到一个可以重用的对象内部(切面),再将其切入
连接点(Joinpoint)
在一个模块的service中会有很多的方法,连接点指的是可以切入的点(程序执行的某一个位置:Spring支持方法连接点:方法调用前,方法调用后,方法抛出异常时)
切点(Pointcut)
切点指的就是特定的连接点,也就是需要切入的连接点(比如add方法的方法调用前)
增强(Advice)
织入目标程序连接点(切点)的一段程序代码,封装在一个类,也称为增强类
目标对象(target)
指的是织入的连接点所属的对象(比如图中的三个service对象)
织入(Weaving)
将增强添加到目标连接点(切点)得到一个过程
编译期织入:使用特殊的Java编译器
类装载期织入:使用特殊的类装载器
动态代理织入:在运行期为目标类添加增强生成子类的方式、
Spring采用动态代理织入,而AspectJ采用编译期织入和类装载器织入.
代理(proxy)
目标对象的类被织入了增强之后,会产生一个结果类(织入并不是直接修改代码,而是重新写了另外一个类),这个结果类就是融合了原有类的逻辑以及增强类的增强的代理类(代理类根据不同的代理模式,可能是原有类的子类也有可能具有相同的接口,可以用相同的方式调用)
切面(aspect)
切面类:在增强类的基础上增加了切点的定义(增强类可以切入到任意切点当中,切面类增加了切点的定义,就限制了切入的位置)
通知类型(相当于就是连接点去掉了具体的方法)
//前置通知:目标方法运行之前调用
//成功返回通知(后置通知)(如果出现异常不会调用):在目标方法运行之后调用
//环绕通知:在目标方法之前和之后都调用,还可以替代原方法
//异常拦截通知:如果出现异常,就会调用
//后置通知(无论是否出现 异常都会调用):在目标方法运行之后调用
原理:创建一个代理类实现目标类的接口,在代理类中包含目标类的对象
创建一个接口,由目标类实现
public interface IUserService {
public void tell();
}
目标类实现接口
import com.test.staticproxy.IUserService;
public class UserService implements IUserService {
@Override
public void tell() {
System.out.println("hello");
}
}
创建代理类,实现同样的接口,其中包含目标类属性
public class UserProxy implements IUserService {
private IUserService userService=new UserService();
@Override
public void tell() {
System.out.println("代理给代理对象加的内容");
userService.tell();
System.out.println("代理给代理对象加的内容");
}
}
静态代理:缺点在于代理的是固定的对象(对象被放在代理类的属性当中)
静态代理代理的是固定对象,可以用动态代理实现代理不同的对象
原理:通过JDK自带的Proxy类来创建一个代理对象,代理类实现目标类得到接口
前提:目标对象必须存在一个接口
必须存在的目标对象的接口
package service;
public interface IService {
void test();
void tell();
}
实现接口的目标对象
package service;
import DAO.UserCveDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import test.User;
import java.util.List;
@Service
public class UserCveService implements IService {
@Autowired
private UserCveDao dao;
@Override
public void test(){
List<User> list = dao.selectMoreTable2();
for (User user:list) {
user.tell();
}
}
@Override
public void tell() {
System.out.println("hello");
}
public UserCveDao getDao() {
return dao;
}
public void setDao(UserCveDao dao) {
this.dao = dao;
}
}
创建代理类生成器(使用的接口是InvocationHandler,其中需要实现的方法是invoke)
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkHandler implements InvocationHandler {
Object subject; //用于存放目标对象
public JdkHandler(Object subject){
this.subject = subject; //构造方法传入目标对象
}
//生成一个代理对象并进行返回,目标对象是subject
public static Object bind(Object subject){
return Proxy.newProxyInstance(JdkHandler.class.getClassLoader(), //加载字节码文件:获取subject和invoke方法
subject.getClass().getInterfaces(), //获取目标对象的接口,实现的代理类实现该接口
new JdkHandler(subject)); //传入生成器对象,来调用invoke方法
}
//bind创建的对象只是实现了目标对象的接口,方法体当中做什么并没有指明
//invoke方法,通过反射的方式可以调用原目标方法,并在之前之后自定义
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("打印日志");
//调用原目标方法
Object object = method.invoke(subject, args);
return object;
}
}
创建代理对象并进行测试
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import proxy.JdkHandler;
import service.IService;
import service.UserCveService;
public class TestProxy {
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContextTag.xml");
UserCveService userCveService = applicationContext.getBean("userCveService",UserCveService.class); //完成控制反转的过程并实现依赖注入如
IService service = (IService) JdkHandler.bind(userCveService);
service.test();
System.out.println("done");
service.tell();
}
}
//这里的切入,会将invoke中的增强切入到目标对象的接口所写到的所有方法中
//method会随着代理对象调用方法的改变而改变
原理:通过创建目标类的子类,作为代理对象,在子类当中拦截目标类的方法并进行加强
不需要目标对象存在接口,改善JDK自带代理方式
导入Cglib所需要的jar包
<dependency>
<groupId>cglibgroupId>
<artifactId>cglib-nodepartifactId>
<version>3.2.4version>
dependency>
创建目标类
package service;
import DAO.UserCveDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import test.User;
import java.util.List;
public class UserCveService {
private UserCveDao dao = new UserCveDao();
@Override
public void test(){
List<User> list = dao.selectMoreTable2();
for (User user:list) {
user.tell();
}
}
@Override
public void tell() {
System.out.println("hello");
}
public UserCveDao getDao() {
return dao;
}
public void setDao(UserCveDao dao) {
this.dao = dao;
}
}
创建一个代理生成器(实现的接口:MethodInterceptor实现intercept方法,用于拦截方法)
package proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MyCglib implements MethodInterceptor {
//创建一个对象生成器
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class aClass){ //传入的不再是目标对象,而是目标对象的类的字节码文件
//设置目标对象的类作为生成代理类的父类
enhancer.setSuperclass(aClass);
//设置回调函数,目的在于调用拦截器的方法
enhancer.setCallback(this);
//创建子类对象并进行返回
return enhancer.create();
}
//实现接口当中的方法,用于拦截方法
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("打印日志");
//调用代理对象的父类同名的方法,代理对象调用不同的方法
Object result= methodProxy.invokeSuper(o,objects);
return result;
}
}
进行测试
import org.junit.Test;
import proxy.MyCglib;
import service.UserCveService;
public class TestCglibProxy {
@Test
public void test(){
MyCglib myCglib = new MyCglib();
UserCveService userCveService = (UserCveService) myCglib.getProxy(UserCveService.class);
userCveService.test();
}
}
用于定位切点所在的方法
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
execution( public void com.test.service.impl.UsersService.add() )
参数列表可以进行设置…表示有无参数均可
`<aop:pointcut expression="execution( *com.test.service.impl.UsersService.add(..))" id="pt"/>
找到service包UserCveService所有作用域类型的test方法
`<aop:pointcut expression="execution(
* service.UserCveService.test())" id="pt"/>
类名可以使用*号,表示任意类
<aop:pointcut expression="execution( * com..*.add(..))" id="pt"/>
使用…来表示当前包,及其子包
<aop:pointcut expression="execution( * com..UsersService.add(..))" id="pt"/>
类名也可以使用 * 加后缀,表示这个后缀的所有类
<aop:pointcut expression="execution( * com..*Service.add(..))" id="pt"/>
方法名可以使用*号,表示任意方法
<aop:pointcut expression="execution( * com..*.*(..))" id="pt"/>
拦截所有save开头的方法
参数列表可以使用 * , 表示可以是任何的数据类型,但必须有参数
<aop:pointcut expression="execution( *com.test.service.impl.UsersService.add(*))" id="pt"/>
全通配方式execution( * ….* ( … ) )
导入相应和AOP相关的jar包
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>4.3.18.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>4.3.18.RELEASEversion>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.8.10version>
dependency>
<dependency>
<groupId>aopalliancegroupId>
<artifactId>aopallianceartifactId>
<version>1.0version>
dependency>
编写增强类
package advice;
import java.util.Date;
public class MyAdvice {
//将这个增强方法的test方法之前
public void before(){
System.out.println("开始时间"+new Date());
}
//将这个增强方法的test方法之后
public void after(){
System.out.println("结束时间"+new Date());
}
}
编写配置文件,创建增强对象,并进行织入
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="myAdvice" class="advice.MyAdvice"/>
<aop:config>
<aop:pointcut id="testBefore" expression="execution(* service.UserCveService.test())"/>
<aop:aspect ref="myAdvice">
<aop:before method="before" pointcut-ref="testBefore"/>
aop:aspect>
aop:config>
beans>
测试aop执行
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.IService;
public class TestAopXml {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext_aop.xml");
IService service = context.getBean("userCveService",IService.class);
//获取的是目标对象的接口,底层是利用JDK自带代理方式,不是Cglib
service.test();
}
}
通知类型:织入时增强相对于目标方法的相对位置:每个通知类型对应一种标签,写在aop:aspect节点下
aop:before通知:在目标方法调用之前执行增强,目标方法会执行
aop:around通知:在目标方法调用时执行,可以放行目标方法(执行目标方法),也可以不放行(相当于直接替代)
在增强类当中加入的around方法需要考虑是否加上point.proceed(),决定是否放行
public void round(ProceedingJoinPoint point) throws Throwable {
//查询方法
System.out.println( "准备在目标方法中添加环绕通知");
if(false)
point.proceed(); //放行目标方法
}
//环绕通知:用增强代码替换目标方法
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("查询所有用户信息");
return point.proceed();// 等价于userDao.select()
}
aop:after通知:在目标方法调用之后执行增强,目标方法会执行
aop:afterReturning通知:目标方法成功执行时执行增强
aop:afterException通知:目标方法抛出异常后执行
注解内容:切点的定义,织入切点通知类型
增强类当中的增强方法的注解:包括切点表达式指出了切点
五种通知类型代表了五种注解类型
package advice;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Before;
import java.util.Date;
@Aspect
public class MyAdvice {
@Before("execution(* service.UserCveService.test())")
//将这个增强方法的test方法之前
public void before(){
System.out.println("开始时间"+new Date());
}
@After("execution(* service.UserCveService.test())")
//将这个增强方法的test方法之后
public void after(){
System.out.println("结束时间"+new Date());
}
}
第二种注解方式:同一个切点需要多次使用
package advice;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import java.util.Date;
@Aspect
public class MyAdvice {
@Pointcut("execution(* service.UserCveService.test())")
public void pointCut(){ }
@Before("MyAdvice.pointCut()")
//将这个增强方法的test方法之前
public void before(){
System.out.println("开始时间"+new Date());
}
@After("MyAdvice.pointCut()")
//将这个增强方法的test方法之后
public void after(){
System.out.println("结束时间"+new Date());
}
}
配置文件开启自动代理
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="service"/>
<context:component-scan base-package="DAO"/>
<bean id="myAdvice" class="advice.MyAdvice"/>
<aop:aspectj-autoproxy/>
beans>
事务是不可分割的一个并发控制单元,以begin/start transaction开始,以commit或rollback结束
commit:提交,表示事务成功进行,数据库进行更新
rollback:回滚,表示事务进行失败,撤销事务中的一切操作
案例:购物车购买商品后,账户余额减 少,仓库商品数量减少,两个操作必须都进行或者都不进行,二者即归为同一事务,若只有其中之一进行则会造成数据库的重大错误
事务的特征ACID
- 原子性:事务是原子工作单位,不可分割
- 一致性:事务完成之后,数据必须保持一致的状态,保持完整性
- 隔离性:一个事务的执行不能被其他的事务影响,解决并发问题
- 持久性:事务一旦提交,会永久的储存,此时回滚已经没有用处
事务的隔离级别(事务的并发问题)
- 读未提交:最低级别,以上情况都无法保证不出现
- 读已提交:可避免脏读
- 可重复读:不能避免幻读的情况,一个事务正在使用一条记录并且未结束,不允许其他事务修改该记录(默认)
- 串行化读:事务一个一个执行,避免所有情况,整张表都不能进行修改,执行效率极慢
案例:另一个业务逻辑需要调用事务当中的方法,会不会导致开启事务
Spring中的传播行为
PROPAGATION_REQUIRED:当前方法必须运行在事务中,如果事务不存在就开启事务(第三方调用方法会开启新的事务)
PROPAGATION_SUPPORTS:表示方法不需要事务的上下文,但是如果事务已经开启,方法在事务中运行(第三方调用不开新事务)
PROPAGATION_MANDATORY:必须在事务中运行,如果不存在事务会抛出异常
PROPAGATION_REQUIRED_NEW:需要在新开启的事务当中运行,假设需要调用方法需要重新开启事务,原来的事务会被挂起
PROPAGATION_NOT_SUPPORTED:该方法不应该运行在事务当中,在第三方调用方法时,如果事务已经开启则将原事务挂起
PROPAGATION_NEVER:方法在被第三方调用的过程当中不应该运行在事务当中,如果有事务在运行则抛出异常
PROPAGATION_NESTED:如果已经存在事务则会在嵌套事务(嵌套一个相同的事务)当中运行,事务不存在则和REQUIRED相同
声明式事务管理,编程式事务管理(已过时)
需要导入Springjdbc进行对mybatis的整合
原来的DAO中利用构造方法手动创建sqlsessionFactory对象
public UserDao() {
InputStream inputStream = UserDao.class.getClassLoader().getResourceAsStream("mapper\\mybatis.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
this.sqlfactory = builder.build(inputStream);
}
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>1.3.2version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.6.RELEASEversion>
dependency>
<bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/webproject?serverTimezone=CST"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="comboPooledDataSource"/>
<property name="configLocation" value="classpath:mapper/mybatis.xml"/>
bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.test.Mapper"/>
bean>
spring会帮助创建一个实现接口的代理对象,其功能就是DAO的功能,在service中只需要把DAO属性改成mapper接口
需要将mapper.xml文件放在java.com.test.Mapper包当中
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>
springMVC是web框架,用于简化用户和程序之间的数据传递
view:jsp文件 user:输入接受信息 controller:组装用户输入的信息
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>4.3.18.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>4.3.18.RELEASEversion>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>taglibsgroupId>
<artifactId>standardartifactId>
<version>1.1.2version>
dependency>
自己创建springMVC配置文件的模板
<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.test.controller">context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
bean>
beans>
<web-app>
<display-name>Archetype Created Web Applicationdisplay-name>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:SpringApplicationContext/applicationContext.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<servlet>
<servlet-name>dispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springMVC/springMVC.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>dispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
注册
Hello World!
package com.test.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/reg")
public String reg(){
return "reg"; //返回字符串即转发到reg.jsp页面,在springMVC.xml中配置加入前后缀
}
}
RequestMapping注解:@RequestMapping(value = "/login", method = RequestMethod.POST)
value:指的是方法(控制器)的路径
method:指的是允许方法的类型
如何从jsp页面传递值给控制器
@RequestMapping(value = "/loginRequest", method = RequestMethod.POST)
public void loginRequest(HttpServletRequest request, HttpServletResponse response){
String email = request.getParameter("email");
String password = request.getParameter("password");
System.out.println(email+password);
}
@RequestMapping(value = "/loginRequest", method = RequestMethod.POST)
public String loginRequest(@RequestParam(value = "email") String email, @RequestParam(value = "password") String password){
boolean userFound = false;
ArrayList<User> list = iuserService.userLoginMessage();
for (User user:list) {
System.out.println(user.getEmail());
if (user.getEmail().equals(email) && user.getPassword().equals(password)){
userFound = true;
break;
}
}
if (userFound)
System.out.println("userFound");
else
System.out.println("userNotFound");
return "account";
}
在路径使用rest风格的时候,需要在requestMapping中添加路径,在方法声明的参数当中需要用@PathVariable注解路径上的参数
<a href="User/login3/zhangsan/123">登录3a><br/>
@RequestMapping("/login3/{aa}/{pwd}")
public String login3(@PathVariable(value="aa") String name,@PathVariable(value="pwd") String pwd)
{
System.out.println(name);
System.out.println(pwd);
return "success";
}
3个通配符:**表示匹配任意路径;*表示匹配任意字符;?表示匹配一个任意字符
直接在方法声明中的参数加入需要组装的一定义类:表单input和成员属性名称相同
@RequestMapping(value = "/loginRequest", method = RequestMethod.POST)
public String loginRequest(UserBasicInfo loginUser){
boolean userFound = false;
ArrayList list = iuserService.userLoginMessage();
for (User user : list) {
if (user.loginConfirm(loginUser)) {
userFound = true;
break;
}
}
if (userFound)
System.out.println("userFound");
else
System.out.println("userNotFound");
return "account";
}
嵌套对象的组装(对象当中包含自定义对象,输入框写名字时用.)
<form action="user2/addUser" method="post">
<input type="text" name="uname" />
<input type="text" name="pwd" />
<input type="text" name="age" />
<input type="text" name="address.province" />
<input type="text" name="address.city" />
<input type="text" name="address.detailAddress" />
<input type="submit" name="sub" value="提交" />
form>
路径:服务器端向客户端(jsp,html),底层依旧是使用request的键值对
方法:存入model或者modelMap以及modelAndView,然后直接返回页面,在页面当中使用el和jstl进行取值
存放的键值对的存储对象都是写在方法的参数当中
@RequestMapping(value = "/**/loginRequest", method = RequestMethod.POST)
public String loginRequest(UserBasicInfo loginUser, Model model){
boolean userFound = false;
User userForReturn = null; //用于登录成功后传递给主页
ArrayList<User> list = iuserService.userLoginMessage();
for (User user : list) {
if (user.loginConfirm(loginUser)) {
userFound = true;
userForReturn = user;
break;
}
}
if (userFound) {
System.out.println("userFound");
model.addAttribute("loginSuccessUserInfo", userForReturn);
return "account";
}
else {
System.out.println("userNotFound");
model.addAttribute("loginFail", "loginFailed");
return "login";
}
}
${loginSuccessUserInfo.username}
map和model的用法相似,只是调用的方法并不同
@RequestMapping(value = "/**/loginRequest", method = RequestMethod.POST)
public String loginRequest(UserBasicInfo loginUser, Map map){
boolean userFound = false;
User userForReturn = null; //用于登录成功后传递给主页
ArrayList<User> list = iuserService.userLoginMessage();
for (User user : list) {
if (user.loginConfirm(loginUser)) {
userFound = true;
userForReturn = user;
break;
}
}
if (userFound) {
System.out.println("userFound");
map.put("loginSuccessUserInfo", userForReturn); //将map放入键值对,并进行传递
return "account";
}
else {
System.out.println("userNotFound");
map.put("loginFail", "loginFailed");
return "login";
}
}
ModelMap的使用方式完全相同
@RequestMapping(value = "/**/loginRequest", method = RequestMethod.POST)
public String loginRequest(UserBasicInfo loginUser, ModelMap map){
boolean userFound = false;
User userForReturn = null; //用于登录成功后传递给主页
ArrayList<User> list = iuserService.userLoginMessage();
for (User user : list) {
if (user.loginConfirm(loginUser)) {
userFound = true;
userForReturn = user;
break;
}
}
if (userFound) {
System.out.println("userFound");
map.put("loginSuccessUserInfo", userForReturn); //将map放入键值对,并进行传递
return "account";
}
else {
System.out.println("userNotFound");
map.put("loginFail", "loginFailed");
return "login";
}
}
将所需要的页面信息和model所带的键值对全部传入ModelAndView,并返回
@RequestMapping(value = "/**/loginRequest", method = RequestMethod.POST)
public ModelAndView loginRequest2(UserBasicInfo loginUser){
boolean userFound = false;
User userForReturn = null;
ModelAndView modelAndView = new ModelAndView();
ArrayList<User> list = iuserService.userLoginMessage();
for (User user : list) {
if (user.loginConfirm(loginUser)) {
userFound = true;
userForReturn = user;
break;
}
}
if (userFound) {
System.out.println("userFound");
//设置modelAndView中的model键值对
modelAndView.addObject("loginSuccessUserInfo", userForReturn);
//设置view:所转发的页面的信息
modelAndView.setViewName("account");
}
else {
System.out.println("userNotFound");
modelAndView.addObject("loginFail", "loginFailed");
modelAndView.setViewName("login");
}
return modelAndView;
}
${user}
利用jstl获取后端controller传输的集合对象
jsp当中session使用el取值
${sessionScope.loginSuccessUserInfo.getPassword()}
利用注解的方式,将存入ModelAndView的某个变量放入session
@SessionAttributes(value = "loginSuccessUserInfo")
@RequestMapping("/selectUsers9")
public String selectUsers9(@CookieValue(value="loginUname") String loginUname) {
//相当于是在cookie中寻找名字为loginUname,并把值赋给对象loginUname
System.out.println(loginUname);
return "showUsers";
}
引入jar包
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.1version>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.4version>
dependency>
配置MultipartResolver
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
p:defaultEncoding="UTF-8"
p:maxUploadSize="5242880"
p:uploadTempDir="file:/d:/file/temp"
/>
jsp表单的编写
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
controller 编写
@Controller
@RequestMapping(value = "/upload")
public class UploadController {
@RequestMapping(value = "/uploadVul")
public ModelAndView uploadVul(UploadVul uploadVul, HttpServletRequest request, @RequestParam(value = "file") MultipartFile file){
try {
//将文件转移到服务器的某个位置
file.transferTo(new File("D:\\java_second\\projectTest1\\src\\main\\webapp\\uploadFile"+file.getOriginalFilename()));
} catch (IOException e) {
e.printStackTrace();
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/WEB-INF/upload");
uploadVul.setDiscover((String) request.getSession().getAttribute("loginSuccessUserInfo"));
return modelAndView;
}
}
方法名称 | 方法解释 |
---|---|
byte [] getBytes() | 获取文件数据 |
String getContentType() | 获取文件MIMETYPE类型,如image/jpeg,text/plain等 |
InputStream getInputStream() | 获取文件输入流 |
String getName() | 获取表单中文件组件的名称 name值! |
String getOriginalFilename() | 获取文件上传的原名 |
long getSize() | 获取文件的字节大小,单位为byte |
boolean isEmpty() | 是否有长传的文件 |
void transferTo(File dest) | 可以将上传的文件保存到指定的文件中 |
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>5.1.2version>
dependency>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor" />
plugins>
在configuration标签中是有顺序的
//分页查询
@Override
public PageInfo<Items> selectItems(int pageindex, int pagesize) {
//开启分页 在后面调用查询语句的时候会加入limit
PageHelper.startPage(pageindex,pagesize);
//调用查询所有的方法 (会被加入limit)
List<Items> itemsList= itemsMapper.selectItems();
//组装pageinfo对象返回
PageInfo<Items> pageInfo=new PageInfo<Items>(itemsList);
return pageInfo;
}
@RequestMapping("/selectItemsListByPage")
public ModelAndView selectItemsListByPage(@RequestParam(value ="pageindex",defaultValue ="1" ) int pageindex)
{
PageInfo<Items> pageInfo = itemsService.selectItems(pageindex,3);
ModelAndView modelAndView=new ModelAndView();
modelAndView.addObject("pageInfo",pageInfo);
modelAndView.setViewName("showItemsByPage");
return modelAndView;
}
${items.name}
总共查询到${pageInfo.total}条记录,
共${pageInfo.pages}页
当前是第${pageInfo.pageNum}页
${i}