ssm-springboot

JavaWebNote

1Spring

1.1自定义工厂demo

为了对Spring原理进行理解,自建工厂将类的实例化交给第三方。
demo结构图如下
在这里插入图片描述
代码如下

package it.lyz.dao.iml;

import it.lyz.dao.IAccount;

public class Account implements IAccount {
    
    
    public void save() {
    
    
        System.out.println("保存了账户!");
    }
}
package it.lyz.dao;

public interface IAccount {
    
    
     void save();
}

package it.lyz.factory;

import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class factorybean {
    
    
    private static Properties prop;
    private static Map<String,Object> beans;
    static {
    
    
        try{
    
    
            prop = new Properties();
            InputStream in = factorybean.class.getClassLoader().getResourceAsStream("bean.properties");
            prop.load(in);
            beans = new HashMap<String, Object>();
            Enumeration keys = prop.keys();
            while (keys.hasMoreElements()){
    
    
                String key = keys.nextElement().toString();
                String path = prop.getProperty(key);
                Object ob = Class.forName(path).newInstance();
                beans.put(key,ob);
            }
        }catch (Exception e){
    
    
            throw new ExceptionInInitializerError("初始化失败");
        }
    }
    public static Object getBeanName(String beanname){
    
    
        return beans.get(beanname);


    }

}

package it.lyz.service.iml;

import it.lyz.dao.IAccount;
import it.lyz.dao.iml.Account;
import it.lyz.factory.factorybean;
import it.lyz.service.IAccountservice;

public class Accountservice implements IAccountservice {
    
    
    private IAccount account = (IAccount)factorybean.getBeanName("Account");
    public void saveAccount() {
    
    
        int i = 1;
    //    IAccount account = (IAccount)factorybean.getBeanName("Account");
        System.out.println(account);
        account.save();
    }
}

package it.lyz.service;

public interface IAccountservice {
    
    
     void saveAccount();
}

package it.lyz.ui;

import it.lyz.dao.IAccount;
import it.lyz.dao.iml.Account;
import it.lyz.factory.factorybean;
import it.lyz.service.IAccountservice;
import it.lyz.service.iml.Accountservice;

public class client {
    
    
    public static void main(String[] args) {
    
    
/*
        IAccountservice accountservice = (Accountservice)factorybean.getBeanName("Accountservice");
       // IAccount account = (Account)factorybean.getBeanName("Account");
        //System.out.println(account);
        System.out.println(accountservice);
        accountservice.saveAccount();
*/
        for(int i=0;i<5;i++) {
    
    
            IAccountservice as = (IAccountservice) factorybean.getBeanName("Accountservice");
            System.out.println(as);
            as.saveAccount();
        }
    }
}

bean.properties配置

Accountservice=it.lyz.service.iml.Accountservice
Account=it.lyz.dao.iml.Account//Accountservice需要写在前面,否则,Accountservice中在方法外面对Account进行初始化会报空指针异常,即无法获取到Account实例

1.2Springxml配置demo

上述工厂demo中的静态工厂才去Spring进行替代
注意:service中的对象参数需要采用property注入,类中需要对该对象参数添加set方法,不然无法成功获取到property,从而报空指针异常
(使用注解时,参数不需要添加set方法)

    <bean id="accountservice" class="it.lyz.service.iml.Accountservice">
        <property name="account" ref="account"></property>
    </bean>

    <bean id="account" class="it.lyz.dao.iml.Account">
    </bean>

1.3构造函数参数与数据集合参数注入

    <bean id="accountService2" class="com.itheima.service.impl.AccountServiceImpl2">
        <property name="name" value="TEST" ></property>
        <property name="age" value="21"></property>
        <property name="birthday" ref="now"></property>
    </bean>


    <!-- 复杂类型的注入/集合类型的注入
        用于给List结构集合注入的标签:
            list array set
        用于个Map结构集合注入的标签:
            map  props
        结构相同,标签可以互换
    -->
    <bean id="accountService3" class="com.itheima.service.impl.AccountServiceImpl3">
        <property name="myStrs">
            <set>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </set>
        </property>

        <property name="myList">
            <array>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </array>
        </property>

        <property name="mySet">
            <list>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </list>
        </property>

        <property name="myMap">
            <props>
                <prop key="testC">ccc</prop>
                <prop key="testD">ddd</prop>
            </props>
        </property>

        <property name="myProps">
            <map>
                <entry key="testA" value="aaa"></entry>
                <entry key="testB">
                    <value>BBB</value>
                </entry>
            </map>
        </property>
    </bean>


1.4创建Bean的三种方式

第一:使用默认构造函数创建
在Spring的配置文件中使用bean标签,配完id和class属性之后,且没有其他属性和标签时。
采用默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建
第二:使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入Spring容器)

<bean id="instanceFactory" class="com.itheima.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>

第三:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入Spring容器)

<bean id="accountService" class="com.itheima.factory.StaticFactory" factory-method="getAccountService"></bean>

1.5Bean的作用范围调整

bean标签的scope属性:
作用:用于指定bean的作用范围
取值:常用的就是单例和多例的
singletom:单例的(默认值)
prototype:多例的
request:作用于web应用的请求范围
session:作用于web应用的会话范围
global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session;

1.6Bean对象的生命周期

单例对象
出生:当容器创建时对象出生
活着:只有容器还在,对象一直活着
死亡:容器销毁,对象消亡
总结:单例对象的生命周期和容器相同
多例对象
出生:当我们使用对象时Spring框架为我们创建
活着:对象只要是在使用过程中就一直活着
死亡:当对象长时间不用,且没有别的对象引用时,由于Java的垃圾回收器回收

1.7基于注解配置Spring

用于创建对象的,相当于:
@Component 自定义类使用这个
@Controller、@Service、Repository 分层使用这个
如果不配置参数,默认为类名,首字母小写

用于注入数据的,相当于property
@Autowired 当有多个 类型匹配时,使用要注入的对象变量名称作为 bean 的 id,在 spring 容器查找,找到了也可以注入成功。找不到 就报错。
@Qualifier 在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。它在给字段注入时不能独立使用,必须和 @Autowire 一起使用;但是给方法参数注入时,可以独立使用。
@Resource 注入基本数据类型和 String 类型数据的

用于改变作用范围的:相当于:
@Scope 指定 bean 的作用范围

和生命周期相关的:
@PostConstruct 用于指定初始化方法。
@PreDestroy 用于指定销毁方法。

1.8使用注解配置时需要注意内容

使用配置文件告知程序Spring框架并开启扫描

<?xml version="1.0" encoding="UTF-8"?>
<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">

    <!-- 告知spring在创建容器时要扫描的包 -->
    <context:component-scan base-package="com.itheima"></context:component-scan>
    
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
    </bean>

  
</beans>
 xmlns:context="http://www.springframework.org/schema/context"
 <context:component-scan base-package="com.itheima"></context:component-scan>

完全避免xml配置,完全使用注解进行配置

//@Configuration//告知程序,这是一个配置类
@ComponentScan("com.itheima")
@Import(JdbcConfig.class)//如果有@Import可以不再写@Configuration注解
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {
    
    
}

@Bean 该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 spring 容器
@PropertySource 用于加载.properties 文件中的配置。用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath:
@Import 用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration 注解。有Import注解的类就父配置类,而导入的都是子配置类

通过注解获取容器需要使用的方法

 ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
 QueryRunner runner = ac.getBean("runner",QueryRunner.class);

通过配置获取容器需要使用的方法

ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
AccountService accountService = (AccountService)ac.getBean("accountService");

1.9Spring整合Junit4完全使用注解

@RunWith(SpringJUnit4ClassRunner.class)//用@RunWith 注解替换原有运行器
@ContextConfiguration(classes = SpringConfiguration.class)//@ContextConfiguration 指定配置类位置
//@ContextConfiguration(locations= {"classpath:bean.xml"})//@ContextConfiguration 指定 spring 配置文件的位置
public class AccountServiceTest {
    
    

    @Autowired
    private IAccountService as = null;

    @Test
    public void testFindAll() {
    
    
        //3.执行方法
        List<Account> accounts = as.findAllAccount();
        for(Account account : accounts){
    
    
            System.out.println(account);
        }
    }
}

2.0动态代理

基于接口的
提供者:JDK 官方的 Proxy 类。 要求:被代理类最少实现一个接口。

public class Client {
    
    
    public static void main(String[] args) {
    
    
        final Poducer poducer = new PoducerImp();
        Poducer proxyPoducer = (Poducer) Proxy.newProxyInstance(poducer.getClass().getClassLoader(),
                poducer.getClass().getInterfaces(),
                new InvocationHandler() {
    
    
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
                        Object returnValue = null;
                        Float money = (Float)args[0];
                        if("saleService".equals(method.getName())){
    
    
                            returnValue = method.invoke(poducer,money*0.8f);
                        }
                        return returnValue;
                    }
                });
        proxyPoducer.saleService(1000f);
    }
}

基于子类的
提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。 要求:被代理类不能用 final 修饰的类(最终类)。
pom.xml

 <dependencies>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.1_3</version>
        </dependency>
    </dependencies>
public class CglibClient {
    
    
    public static void main(String[] args) {
    
    
        final Poducerc poducerc = new Poducerc();
        Poducerc cglibPoducer = (Poducerc) Enhancer.create(poducerc.getClass(), new MethodInterceptor() {
    
    
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    
                Object returnValue = null;
                Float money = (Float)objects[0];
                if ("saleService".equals(method.getName())){
    
    
                    returnValue = method.invoke(poducerc,money*0.8f);
                }
                return returnValue;
            }
        });
        cglibPoducer.saleService(1000f);
    }
}

2.1通过代理解决事务控制demo

package it.lyz.dao.impl;

import it.lyz.dao.IAccountDao;
import it.lyz.domain.Account;
import it.lyz.utils.ConnectionUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.util.List;

public class AccountDaoImpl implements IAccountDao {
    
    
    private QueryRunner runner;
    private ConnectionUtils connectionUtils;

    public void setRunner(QueryRunner runner) {
    
    
        this.runner = runner;
    }

    public void setConnectionUtils(ConnectionUtils connectionUtils) {
    
    
        this.connectionUtils = connectionUtils;
}

    @Override
    public List<Account> findAllAccount() {
    
    
        try{
    
    
            return runner.query(connectionUtils.getTreadConnection(),"select * from account",new BeanListHandler<Account>(Account.class));
        }catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }

    @Override
    public Account findAccountById(Integer accountId) {
    
    
        try{
    
    
            return runner.query(connectionUtils.getTreadConnection(),"select * from account where id = ? ",new BeanHandler<Account>(Account.class),accountId);
        }catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }

    @Override
    public void saveAccount(Account account) {
    
    
        try{
    
    
            runner.update(connectionUtils.getTreadConnection(),"insert into account(name,money)values(?,?)",account.getName(),account.getMoney());
        }catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }

    @Override
    public void updateAccount(Account account) {
    
    
        try{
    
    
            runner.update(connectionUtils.getTreadConnection(),"update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
        }catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }

    @Override
    public void deletAccount(Integer accountId) {
    
    
        try{
    
    
            runner.update(connectionUtils.getTreadConnection(),"delete from account where id=?",accountId);
        }catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }

    @Override
    public Account findAccountByName(String accountName) {
    
    
        try{
    
    
            List<Account> accounts = runner.query(connectionUtils.getTreadConnection(),"select * from account where name = ? ",new BeanListHandler<Account>(Account.class),accountName);
            if(accounts == null || accounts.size() == 0){
    
    
                return null;
            }
            if(accounts.size() > 1){
    
    
                throw new RuntimeException("结果集不唯一,数据有问题");
            }
            return accounts.get(0);
        }catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }
}

package it.lyz.domain;

import java.io.Serializable;

public class Account implements Serializable {
    
    
    private Integer id;
    private String name;
    private Float money;

    public Integer getId() {
    
    
        return id;
    }

    public void setId(Integer id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Float getMoney() {
    
    
        return money;
    }

    public void setMoney(Float money) {
    
    
        this.money = money;
    }

    @Override
    public String toString() {
    
    
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

package it.lyz.factory;

import it.lyz.service.IAccountService;
import it.lyz.utils.TransactionManager;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class BeanFactory {
    
    

    private IAccountService accountService ;

    private TransactionManager transactionManager;

    public void setTransactionManager(TransactionManager transactionManager){
    
    
        this.transactionManager = transactionManager;
    }

    public final void setAccountService(IAccountService accountService){
    
    
        this.accountService = accountService;
    }



    public IAccountService getAccountService(){
    
    
        return  (IAccountService)Proxy.newProxyInstance(accountService.getClass().getClassLoader(),
                accountService.getClass().getInterfaces(),
                new InvocationHandler() {
    
    

                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    

                            if("test".equals(method.getName())){
    
    
                                return method.invoke(accountService,args);
                            }

                            Object rtValue = null;
                            try {
    
    
                                //1.开启事务
                                transactionManager.beginTransaction();
                                //2.执行操作
                                rtValue = method.invoke(accountService, args);
                                //3.提交事务
                                transactionManager.commit();
                                //4.返回结果
                                //System.out.println(rtValue);
                                return rtValue;

                            } catch (Exception e) {
    
    
                                //5.回滚操作
                                transactionManager.rollback();
                                throw new RuntimeException(e);
                            } finally {
    
    
                                //6.释放连接
                                transactionManager.release();
                            }
                        }
                    });
    }
}

package it.lyz.service.impl;

import it.lyz.dao.IAccountDao;
import it.lyz.domain.Account;
import it.lyz.service.IAccountService;

import java.util.List;

public class AccountServiceImpl implements IAccountService {
    
    
    private IAccountDao accountDao ;
    public void setAccountDao(IAccountDao accountDao){
    
    
         this.accountDao = accountDao;
    }

    @Override
    public List<Account> findAccountAll() {
    
    
        return accountDao.findAllAccount();
    }

    @Override
    public Account findAccountById(Integer accountId) {
    
    
        return accountDao.findAccountById(accountId);
    }


    @Override
    public void saveAccount(Account account) {
    
    
        accountDao.saveAccount(account);

    }

    @Override
    public void updateAccount(Account account) {
    
    
        accountDao.updateAccount(account);

    }

    @Override
    public void deletAccount(Integer accountId) {
    
    
        accountDao.deletAccount(accountId);

    }

    @Override
    public void tansfer(String sourceName, String targetName, Float money) {
    
    
        Account sourceAccount = accountDao.findAccountByName(sourceName);
        Account targetAccount = accountDao.findAccountByName(targetName);
        sourceAccount.setMoney(sourceAccount.getMoney()-money);
        targetAccount.setMoney(targetAccount.getMoney()+money);
        accountDao.updateAccount(sourceAccount);
        accountDao.updateAccount(targetAccount);

    }
}

package it.lyz.utils;

import javax.sql.DataSource;
import java.sql.Connection;

public class ConnectionUtils {
    
    
    private ThreadLocal<Connection> tl = new ThreadLocal<Connection>();

    private DataSource dataSource ;

    public void setDataSource(DataSource dataSource){
    
    
        this.dataSource = dataSource;
    }

    public Connection getTreadConnection(){
    
    
        try {
    
    
            Connection connection = tl.get();
            if (connection == null){
    
    
                connection = dataSource.getConnection();
                tl.set(connection);
            }
            return connection;
        }catch (Exception e){
    
    
            throw new RuntimeException(e);
        }
    }

    public void removeConnection(){
    
    
        tl.remove();
    }
}

package it.lyz.utils;

import java.sql.SQLException;

public class TransactionManager {
    
    

    private ConnectionUtils connectionUtils;

    public void setConnectionUtils(ConnectionUtils connectionUtils){
    
    
        this.connectionUtils = connectionUtils;
    }

    public void beginTransaction(){
    
    
        try {
    
    
            connectionUtils.getTreadConnection().setAutoCommit(false);
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
    }

    public void commit(){
    
    
        try {
    
    
            connectionUtils.getTreadConnection().commit();
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
    }

    public void rollback(){
    
    
        try {
    
    
            connectionUtils.getTreadConnection().rollback();
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
    }

    public void release(){
    
    
        try {
    
    
            connectionUtils.getTreadConnection().close();
            connectionUtils.removeConnection();
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置代理的service-->
    <bean id="proxyAccountService" factory-bean="beanFactory" factory-method="getAccountService">

    </bean>


    <!--配置factory-->
    <bean id="beanFactory" class="it.lyz.factory.BeanFactory">
        <property name="accountService" ref="accountService"></property>
        <property name="transactionManager" ref="transactionManager"></property>
    </bean>

    <!--配置service-->
    <bean id="accountService" class="it.lyz.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>

    <!--配置dao-->
    <bean id="accountDao" class="it.lyz.dao.impl.AccountDaoImpl">
        <property name="runner" ref="runner"></property>
        <property name="connectionUtils" ref="connectionUtils"></property>

        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <!--配置utils-->
    <bean id="connectionUtils" class="it.lyz.utils.ConnectionUtils">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置事务管理-->
    <bean id="transactionManager" class="it.lyz.utils.TransactionManager">
        <property name="connectionUtils" ref="connectionUtils"></property>
    </bean>

    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--连接数据库的必备信息-->
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/account"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype"></bean>


</beans>
import it.lyz.service.IAccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class TestAccount {
    
    
    @Autowired
    @Qualifier("proxyAccountService")
    private IAccountService as;
    @Test
    public void testTransfer(){
    
    
        as.tansfer("bbb","aaa",1f);
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>AccountProxy</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>6</source>
                    <target>6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.4</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

    <pluginRepositories>
        <pluginRepository>
            <id>alimaven spring plugin</id>
            <name>alimaven spring plugin</name>
            <url>https://maven.aliyun.com/repository/spring-plugin</url>
        </pluginRepository>
    </pluginRepositories>

</project>

2.2通知demo

切入点表达式execution
访问修饰符 返回值 包名.包名.包名…类名.方法名(参数列表)
方位修饰符可以省略

xml中的空间名配置,查看spring核心代码文档5.3.2,或者搜索 Declaring a pointcut (第二个,第一个是注解配置,第二个是xml配置)

demo工程结构如下:

it.lyz.service.impl.AccountServiceImpl
it.lyz.utils.Logger
LoggerTest

实际开发通用写法,切到业务层实现类所有方法

com.itheima.service.impl.*.*(..)
此处注意所有的id都必须唯一,包括切面配置id都不能够与其他id产生冲突
<?xml version="1.0" encoding="UTF-8"?>
<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">

    <!-- an HTTP Session-scoped bean exposed as a proxy -->
    <bean id="accountService" class="it.lyz.service.impl.AccountServiceImpl" ></bean>

    <!-- a singleton-scoped bean injected with a proxy to the above bean -->
    <bean id="logger" class="it.lyz.utils.Logger"></bean>

    <aop:config>
        <aop:aspect id="logAdvice" ref="logger">

            <aop:pointcut id="PointcutAccountService"
                          expression="execution(* it.lyz.service.impl.*.*(..)) "/>

            <aop:before pointcut-ref="PointcutAccountService" method="logger"/>

        </aop:aspect>
    </aop:config>
</beans
或者: 
<aop:config>
        <!--配置切面 -->
        <aop:aspect id="logAdvice" ref="logger">
            <!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
            <aop:before method="printLog" pointcut="execution(* com.itheima.service.impl.*.*(..))"></aop:before>
        </aop:aspect>
    </aop:config>

2.3环绕通知

<?xml version="1.0" encoding="UTF-8"?>
<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">

    <!-- 配置srping的Ioc,把service对象配置进来-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>


    <!-- 配置Logger类 -->
    <bean id="logger" class="com.itheima.utils.Logger"></bean>

    <!--配置AOP-->
    <aop:config>
        <!-- 配置切入点表达式 id属性用于指定表达式的唯一标识。expression属性用于指定表达式内容
              此标签写在aop:aspect标签内部只能当前切面使用。
              它还可以写在aop:aspect外面,此时就变成了所有切面可用
          -->
        <aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut>
        <!--配置切面 -->
        <aop:aspect id="logAdvice" ref="logger">
            <!-- 配置前置通知:在切入点方法执行之前执行
            <aop:before method="beforePrintLog" pointcut-ref="pt1" ></aop:before>-->

            <!-- 配置后置通知:在切入点方法正常执行之后值。它和异常通知永远只能执行一个
            <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>-->

            <!-- 配置异常通知:在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个
            <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>-->

            <!-- 配置最终通知:无论切入点方法是否正常执行它都会在其后面执行
            <aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>-->

            <!-- 配置环绕通知 详细的注释请看Logger类中-->
            <aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around>
        </aop:aspect>
    </aop:config>

</beans>
   /**
     * 环绕通知
     * 问题:
     *      当我们配置了环绕通知之后,切入点方法没有执行,而通知方法执行了。
     * 分析:
     *      通过对比动态代理中的环绕通知代码,发现动态代理的环绕通知有明确的切入点方法调用,而我们的代码中没有。
     * 解决:
     *      Spring框架为我们提供了一个接口:ProceedingJoinPoint。该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。
     *      该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用。
     *
     * spring中的环绕通知:
     *      它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。
     */
    public Object aroundPringLog(ProceedingJoinPoint pjp){
    
    
        Object rtValue = null;
        try{
    
    
            Object[] args = pjp.getArgs();//得到方法执行所需的参数

            System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置");

            rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法)

            System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置");

            return rtValue;
        }catch (Throwable t){
    
    
            System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常");
            throw new RuntimeException(t);
        }finally {
    
    
            System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");
        }
    }

2.4注解配置环绕通知demo

<?xml version="1.0" encoding="UTF-8"?>
<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"
       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.xsd">

    <!-- 配置spring创建容器时要扫描的包 去核心代码文档中查找context:component-->
    <context:component-scan base-package="it.lyz"/>
    
    <!-- 配置spring开启注解AOP的支持 去核心代码文档中查找aop:aspectj-->
    <aop:aspectj-autoproxy/>

</beans>
package it.lyz.service.impl;

import it.lyz.service.AccountService;
import org.springframework.stereotype.Service;

@Service("accountService")
public class AccountServiceImpl implements AccountService {
    
    
    public void saveAccount() {
    
    
        System.out.println("保存账户");
    }
}

package it.lyz.utlis;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component("logger")
@Aspect//表示当前类是一个切面类
public class Logger {
    
    

    @Pointcut("execution(* it.lyz.service.impl.*.*(..))")
    private void pt(){
    
    };

    @Around("pt()")
    public Object arroundLogger(ProceedingJoinPoint pjp){
    
    
        Object rtvalue = null;
        try {
    
    
            Object args[] = pjp.getArgs();
            System.out.println("前置通知");
            rtvalue = pjp.proceed(args);
            System.out.println("后置通知");
            return rtvalue;
        } catch (Throwable t) {
    
    
            System.out.println("异常通知");
            throw new  RuntimeException(t);
        }finally {
    
    
            System.out.println("最终通知");
        }
    }
}

2.5spring声明式事务配置demo (没有从官方文档中找到相关配置 )

注:此处理解与记忆比较生疏,需要多加练习

<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 配置业务层-->
    <bean id="accountService" class="it.lyz.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>

    <!-- 配置账户的持久层-->
    <bean id="accountDao" class="it.lyz.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>


    <!-- 配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/account"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <!-- 配置事务管理器 -->
    <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>
            <tx:method name="*" propagation="REQUIRED" read-only="false"/>
            <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>

    </tx:advice>

    <!-- 配置aop-->
    <aop:config>
        <aop:pointcut id="pt" expression="execution(* it.lyz.service.impl.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
    </aop:config>

</beans>

<!-- 配置事务的属性
                isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
                propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
                read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
                timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
                rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
                no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
        -->
 <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>6</source>
                    <target>6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

    <pluginRepositories>
        <pluginRepository>
            <id>alimaven spring plugin</id>
            <name>alimaven spring plugin</name>
            <url>https://maven.aliyun.com/repository/spring-plugin</url>
        </pluginRepository>
    </pluginRepositories>

2.6spring声明式事务基于注解配置

    <!-- 配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 开启spring对注解事务的支持-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
package com.itheima.dao.impl;

import com.itheima.dao.IAccountDao;
import com.itheima.domain.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 账户的持久层实现类
 */
@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao {
    
    

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public Account findAccountById(Integer accountId) {
    
    
        List<Account> accounts = jdbcTemplate.query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),accountId);
        return accounts.isEmpty()?null:accounts.get(0);
    }

    @Override
    public Account findAccountByName(String accountName) {
    
    
        List<Account> accounts = jdbcTemplate.query("select * from account where name = ?",new BeanPropertyRowMapper<Account>(Account.class),accountName);
        if(accounts.isEmpty()){
    
    
            return null;
        }
        if(accounts.size()>1){
    
    
            throw new RuntimeException("结果集不唯一");
        }
        return accounts.get(0);
    }

    @Override
    public void updateAccount(Account account) {
    
    
        jdbcTemplate.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
    }
}

package com.itheima.service.impl;

import com.itheima.dao.IAccountDao;
import com.itheima.domain.Account;
import com.itheima.service.IAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * 账户的业务层实现类
 *
 * 事务控制应该都是在业务层
 */
@Service("accountService")
@Transactional(propagation= Propagation.SUPPORTS,readOnly=true)//只读型事务的配置
public class AccountServiceImpl implements IAccountService{
    
    

    @Autowired
    private IAccountDao accountDao;


    @Override
    public Account findAccountById(Integer accountId) {
    
    
        return accountDao.findAccountById(accountId);

    }


    //需要的是读写型事务配置
    @Transactional(propagation= Propagation.REQUIRED,readOnly=false)
    @Override
    public void transfer(String sourceName, String targetName, Float money) {
    
    
        System.out.println("transfer....");
            //2.1根据名称查询转出账户
            Account source = accountDao.findAccountByName(sourceName);
            //2.2根据名称查询转入账户
            Account target = accountDao.findAccountByName(targetName);
            //2.3转出账户减钱
            source.setMoney(source.getMoney()-money);
            //2.4转入账户加钱
            target.setMoney(target.getMoney()+money);
            //2.5更新转出账户
            accountDao.updateAccount(source);

            int i=1/0;

            //2.6更新转入账户
            accountDao.updateAccount(target);
    }
}

package config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;

/**
 * 和连接数据库相关的配置类
 */
public class JdbcConfig {
    
    

    @Value("${jdbc.driver}")
    private String driver;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    /**
     * 创建JdbcTemplate
     * @param dataSource
     * @return
     */
    @Bean(name="jdbcTemplate")
    public JdbcTemplate createJdbcTemplate(DataSource dataSource){
    
    
        return new JdbcTemplate(dataSource);
    }

    /**
     * 创建数据源对象
     * @return
     */
    @Bean(name="dataSource")
    public DataSource createDataSource(){
    
    
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        return ds;
    }
}

package config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * spring的配置类,相当于bean.xml
 */
@Configuration
@ComponentScan("com.itheima")
@Import({
    
    JdbcConfig.class,TransactionConfig.class})
@PropertySource("jdbcConfig.properties")
@EnableTransactionManagement
public class SpringConfiguration {
    
    
}

package config;

import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

/**
 * 和事务相关的配置类
 */
public class TransactionConfig {
    
    

    /**
     * 用于创建事务管理器对象
     * @param dataSource
     * @return
     */
    @Bean(name="transactionManager")
    public PlatformTransactionManager createTransactionManager(DataSource dataSource){
    
    
        return new DataSourceTransactionManager(dataSource);
    }
}

//jdbcConfig.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy
jdbc.username=root
jdbc.password=1234

2SpringMVC

2.1springmvc入门demo

创建工程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RoBJquux-1614575123090)(C:\marknote\tupian\SpringMVCwebapp.bmp)]

添加键值对解决创建过慢问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bRiRah0n-1614575123096)(C:\marknote\tupian\SpringMVC解决创建过慢问题.bmp)]

工程结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c8Yuo7Zj-1614575123100)(C:\marknote\tupian\springmvc1工程结构.bmp)]

webxml配置

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!-- 配置 spring mvc 的核心控制器 前端控制器-->
  <servlet>
    <servlet-name>SpringMVCDispatcherServlet</servlet-name>
    <servlet-class>
      org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <!-- 配置初始化参数,用于读取 SpringMVC 的配置文件 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!-- 配置 servlet 的对象的创建时间点:应用加载时创建。
    取值只能是非 0 正整数,表示启动顺序 -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>SpringMVCDispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

springmvc.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/mvc
          http://www.springframework.org/schema/mvc/spring-mvc.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 开启注解扫描 -->
    <context:component-scan base-package="it.lyz.controller"/>

    <!-- 视图解析器对象 -->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>


</beans>

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>it.lyz</groupId>
  <artifactId>SpringMVCW</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>SpringMVCW Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
    <spring.version>5.0.2.RELEASE</spring.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
      <scope>provided</scope>
    </dependency>

  </dependencies>

  <build>
    <finalName>SpringMVCW</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

package it.lyz.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HelloController {
    
    
    @RequestMapping("hello")
    public String helloPrint(){
    
    
        System.out.println("hello lyz ****");
        return "success";
    }
}
//@RequestMapping也可以配置在类上面,使得项目可以模块化访问
//其中vallue=path,可以互换,当参数唯一时可以省略。还可以增加其它params、method与heads等其他参数,用得少。
<%--success
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2021/1/21
  Time: 15:50
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <h3>lyz入门成功</h3>
</head>
<body>

</body>
</html>

<%--index
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2021/1/21
  Time: 15:46
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <h3>hello lyz</h3>
    <a href="hello">点击跳转</a>
</head>
<body>

</body>
</html>

2.2springmvc传参数

过滤器解决乱码问题(web.xml)

<!--配置解决中文乱码的过滤器-->
  <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>

写好实体类,form表单中有对应的键值对会自动封装到javaBean中去,如果是实体类中存在引用类型的参数,则需要注意一些细节:采用“user.*”形式会封装进引用类型参数

   把数据封装Account类中
    <form action="param/saveAccount" method="post">
        姓名:<input type="text" name="username" /><br/>
        密码:<input type="text" name="password" /><br/>
        金额:<input type="text" name="money" /><br/>
        用户姓名:<input type="text" name="user.uname" /><br/>
        用户年龄:<input type="text" name="user.age" /><br/>
        <input type="submit" value="提交" />
    </form>

自定义转换数据格式(springmvc.xml)

  <!--配置自定义类型转换器-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="it.lyz.utils.StringToDateConverter"></bean>
            </set>
        </property>
    </bean>

    <!-- 开启SpringMVC框架注解的支持 在上一个demo中可配可不配-->
    <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
//重写conveter接口
package it.lyz.utils;

import org.springframework.core.convert.converter.Converter;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class StringToDateConverter implements Converter<String,Date> {
    
    

    @Override
    public Date convert(String source) {
    
    
        if (source == null){
    
    
            System.out.println("日期数据为空,请传输日期");
        }
        DateFormat df = new SimpleDateFormat("yyyy-mm-dd");
        try {
    
    
            return df.parse(source);
        } catch (Exception e) {
    
    
            throw new RuntimeException("日期数据转换失败");
        }
    }
}

2.3springmvc常用注解

把请求中的指定名称的参数传递给控制器中的形参赋值

   @RequestMapping("/testRequestParam")
    //使用@RequestParam(name="name")注解时,未规定required=false,name必须传,且键名必须为"name"。"name"的值将会与"username"绑定。[value与name效果相同]
    public String testRequestParam(@RequestParam(name="name") String username){
    
    
        System.out.println("执行了...");
        System.out.println(username);
        return "success";
    }

获取请求体

   /**
     * 获取到请求体的内容
     * @return
     */
    @RequestMapping("/testRequestBody")
    public String testRequestBody(@RequestBody String body){
    
    
        System.out.println("执行了...");
        System.out.println(body);//username=hehe&age=20
        return "success";
    }

获取请求头

@RequestHeader(value="Accept") String header

获取cookie

@CookieValue(value="JSESSIONID") String cookieValue

restful风格


    /**
     * PathVariable注解
     * @return
     */
    @RequestMapping(value="/testPathVariable/{sid}")
    //@RequestMapping中占位符的字符数"sid",则@PathVariable中的name也必须为"sid",传参的时候,在地址后直接带上参数会访问到该方法并传入参数。不带参数便访问其他方法
    //eg:<a href="anno/testPathVariable/10">testPathVariable</a>
    public String testPathVariable(@PathVariable(name="sid") String id){
    
    
        System.out.println("执行了...");
        System.out.println(id);
        return "success";
    }

@ModelAttribute,应该会对user进行重新封装再传入被访问目标方法中

  /**
     * ModelAttribute注解
     * @return
     */
    @RequestMapping(value="/testModelAttribute")
    public String testModelAttribute(@ModelAttribute("abc") User user){
    
    
        System.out.println("testModelAttribute执行了...");
        System.out.println(user);
        return "success";
    }

    @ModelAttribute
    public void showUser(String uname, Map<String,User> map){
    
    
        System.out.println("showUser执行了...");
        // 通过用户查询数据库(模拟)
        User user = new User();
        user.setUname(uname);
        user.setAge(20);
        user.setDate(new Date());
        map.put("abc",user);
    }

    /**提交表单 
       <form action="anno/testModelAttribute" method="post">
        用户姓名:<input type="text" name="uname" /><br/>
        用户年龄:<input type="text" name="age" /><br/>
        <input type="submit" value="提交" />
        </form>
     * 该方法会先执行

    @RequestMapping(value="/testModelAttribute")
    public String testModelAttribute(User user){
        System.out.println("testModelAttribute执行了...");
        System.out.println(user);
        return "success";
    }

    @ModelAttribute
    public User showUser(String uname){
        System.out.println("showUser执行了...");
        // 通过用户查询数据库(模拟)
        User user = new User();
        user.setUname(uname);
        user.setAge(20);
        user.setDate(new Date());
        return user;
    }
     */

@SessionAttributes

/**
 * 常用的注解
 */
@Controller
@RequestMapping("/anno")
@SessionAttributes(value={
    
    "msg"})   // 把msg=美美存入到session域对中
public class AnnoController {
    
    
    /**
     * SessionAttributes的注解
     * @return
     */
    @RequestMapping(value="/testSessionAttributes")
    public String testSessionAttributes(Model model){
    
    
        System.out.println("testSessionAttributes...");
        // 底层会存储到request域对象中,如果不加@SessionAttributes则只存在request对象中
        model.addAttribute("msg","美美");
        return "success";
    }

    /**
     * 获取值
     * @param modelMap
     * @return
     */
    @RequestMapping(value="/getSessionAttributes")
    public String getSessionAttributes(ModelMap modelMap){
    
    
        //获取值需要使用model的继承类
        System.out.println("getSessionAttributes...");
        String msg = (String) modelMap.get("msg");
        System.out.println(msg);
        return "success";
    }

    /**
     * 清除session
     * @param status
     * @return
     */
    @RequestMapping(value="/delSessionAttributes")
    public String delSessionAttributes(SessionStatus status){
    
    
        System.out.println("getSessionAttributes...");
        status.setComplete();
        return "success";
    }
}
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<!--开启表达式 isELIgnored="false"-->
<html>
<head>
    <title>Title</title>
</head>
<body>

    <h3>入门成功</h3>
    
    ${requestScope}

    ${ msg }

    ${sessionScope}

</body>
</html>

2.4响应数据和结果视图

 /**
     * 返回String
     * @param model
     * @return
     */
    @RequestMapping("/testString")
    public String testString(Model model){
    
    //传入model才能使用model
        System.out.println("testString方法执行了...");
        // 模拟从数据库中查询出User对象
        User user = new User();
        user.setUsername("美美");
        user.setPassword("123");
        user.setAge(30);
        // model对象
        model.addAttribute("user",user);
        return "success";
    }

    /**
     * 是void
     * 请求转发一次请求,不用编写项目的名称
     */
    @RequestMapping("/testVoid")
    public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
    
        System.out.println("testVoid方法执行了...");
        // 编写请求转发的程序
        // request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);

        // 重定向
        // response.sendRedirect(request.getContextPath()+"/index.jsp");

        // 设置中文乱码
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        // 直接会进行响应
        response.getWriter().print("你好");

        return;
    }

    /**
     * 返回ModelAndView
     * @return
     */
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
    
    
        // 创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        System.out.println("testModelAndView方法执行了...");
        // 模拟从数据库中查询出User对象
        User user = new User();
        user.setUsername("小凤");
        user.setPassword("456");
        user.setAge(30);

        // 把user对象存储到mv对象中,也会把user对象存入到request对象
        mv.addObject("user",user);

        // 跳转到哪个页面
        mv.setViewName("success");//自主调用视图

        return mv;
    }

//SpringMVC的关键字进行数据转发与重定向用不到视图,不会用到视图配置中的地址,需要自己补全地址
//它相当于“response.sendRedirect(url)”。需要注意的是,如果是重定向到 jsp 页面,则 jsp 页面不
//能写在 WEB-INF 目录中,否则无法找到。
 /**
     * 使用关键字的方式进行转发或者重定向
     * @return
     */
    @RequestMapping("/testForwardOrRedirect")
    public String testForwardOrRedirect(){
    
    
        System.out.println("testForwardOrRedirect方法执行了...");

        // 请求的转发
        // return "forward:/WEB-INF/pages/success.jsp";

        // 重定向 底层自动加上了项目名
        return "redirect:/index.jsp";
    }

2.5前端控制器过滤静态资源(放行部分)

springmvc.xml

    <!--前端控制器,哪些静态资源不拦截-->
    <mvc:resources location="/css/" mapping="/css/**"/>
    <mvc:resources location="/images/" mapping="/images/**"/>
    <mvc:resources location="/js/" mapping="/js/**"/>

requestbody

pom.xml

<!--引入jackson,可以自动封装javabean-->
<dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.0</version>
    </dependency>
  /**使用关键字@ResponseBody 返回数据 @RequestBody 接收数据
     * 模拟异步请求响应
     */
    @RequestMapping("/testAjax")
    public @ResponseBody User testAjax(@RequestBody User user){
    
    
        System.out.println("testAjax方法执行了...");
        // 客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中
        System.out.println(user);
        // 做响应,模拟查询数据库
        user.setUsername("haha");
        user.setAge(40);
        // 做响应
        return user;
    }
 <script src="js/jquery.min.js"></script>

    <script>
        // 使用原始ajax演示 表现内部传参过程更加清晰
        // 页面加载,绑定单击事件
        $(function(){
            $("#btn").click(function(){
                // alert("hello btn");
                // 发送ajax请求
                $.ajax({
                    // 编写json格式,设置属性和值
                    url:"user/testAjax",
                    contentType:"application/json;charset=UTF-8",
                    data:'{"username":"hehe","password":"123","age":30}',
                    dataType:"json",
                    type:"post",
                    success:function(data){
                        // data服务器端响应的json的数据,进行解析
                        alert(data);
                        alert(data.username);
                        alert(data.password);
                        alert(data.age);
                    }
                });

            });
        });

    </script>

2.6传统方式上传文件

上传文件时,大于10kb时,会生成临时文件,当文件传输完毕需要申请删除。当文件小于10kb时,则会生成在缓存当中,这样的不需要我们去处理。

 <form action="/user/fileupload1" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload" /><br/>
        <input type="submit" value="上传" />
 </form>
   /**
     * 文件上传
     * @return
     */
    @RequestMapping("/fileupload1")
    public String fileuoload1(HttpServletRequest request) throws Exception {
    
    
        System.out.println("文件上传...");

        // 使用fileupload组件完成文件上传
        // 上传的位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        // 判断,该路径是否存在
        File file = new File(path);
        if(!file.exists()){
    
    
            // 创建该文件夹
            file.mkdirs();
        }

        // 解析request对象,获取上传文件项
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        // 解析request
        List<FileItem> items = upload.parseRequest(request);
        // 遍历
        for(FileItem item:items){
    
    
            // 进行判断,当前item对象是否是上传文件项
            if(item.isFormField()){
    
    
                // 说明普通表单向
            }else{
    
    
                // 说明上传文件项
                // 获取上传文件的名称
                String filename = item.getName();
                // 把文件的名称设置唯一值,uuid
                String uuid = UUID.randomUUID().toString().replace("-", "");
                filename = uuid+"_"+filename;
                // 完成文件上传
                item.write(new File(path,filename));
                // 删除临时文件
                item.delete();
            }
        }

        return "success";
    }

2.7SpringMVC上传文件

文件解析器配置中的id必须固定不变
形参“upload"需要与上传表单名称一样

 /**
     * SpringMVC文件上传
     * @return
     */
    @RequestMapping("/fileupload2")
    public String fileuoload2(HttpServletRequest request, MultipartFile upload) throws Exception {
    
    
        System.out.println("springmvc文件上传...");

        // 使用fileupload组件完成文件上传
        // 上传的位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        // 判断,该路径是否存在
        File file = new File(path);
        if(!file.exists()){
    
    
            // 创建该文件夹
            file.mkdirs();
        }

        // 说明上传文件项
        // 获取上传文件的名称
        String filename = upload.getOriginalFilename();
        // 把文件的名称设置唯一值,uuid
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid+"_"+filename;
        // 完成文件上传
        upload.transferTo(new File(path,filename));

        return "success";
    }

2.8跨服务器上传文件

引入sun提供的两个iar包
jersey-client
jersey-core

   /**
     * 跨服务器文件上传
     * @return
     */
    @RequestMapping("/fileupload3")
    public String fileuoload3(MultipartFile upload) throws Exception {
    
    
        System.out.println("跨服务器文件上传...");

        // 定义上传文件服务器路径
        String path = "http://localhost:9090/uploads/";

        // 说明上传文件项
        // 获取上传文件的名称
        String filename = upload.getOriginalFilename();
        // 把文件的名称设置唯一值,uuid
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid+"_"+filename;

        // 创建客户端的对象
        Client client = Client.create();

        // 和图片服务器进行连接
        WebResource webResource = client.resource(path + filename);

        // 上传文件
        webResource.put(upload.getBytes());

        return "success";
    }

2.9SpringMVC拦截器

过滤器是servlet中的一部分,使用与不使用SpringMVC都可以使用过滤器。控制前端页面,如果url-pattern写为”/*“,则过滤器对所有进行拦截,而拦截器直拦截Controller中的方法

SpringMVC拦截器相当与servlet中的过滤器,控制Controller

SpringMVC的拦截器预处理与后处理接口都可以定义跳转页面,当后处理定义了跳转页面,并且预处理放行了方法时(当方法中返回了页面),方法会执行(只在控制台输出),但是跳转的是后处理定义的页面。

每加一个拦截器都需要再添加一个新的拦截器配置

当有拦截器1与拦截器2时,执行顺序是“前置1-前置2-后置2-后置1-最终2-最终1”

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>cn.itcast</groupId>
  <artifactId>springmvc_day02_04_interceptor</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>springmvc_day02_04_interceptor Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <spring.version>5.0.2.RELEASE</spring.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>springmvc_day02_04_interceptor</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.7.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.20.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 开启注解扫描 -->
    <context:component-scan base-package="cn.itcast"/>

    <!-- 视图解析器对象 -->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--前端控制器,哪些静态资源不拦截-->
    <mvc:resources location="/css/" mapping="/css/**"/>
    <mvc:resources location="/images/" mapping="/images/**"/>
    <mvc:resources location="/js/" mapping="/js/**"/>

    <!--配置拦截器-->
    <mvc:interceptors>
        <!--配置拦截器-->
        <mvc:interceptor>
            <!--要拦截的具体的方法-->
            <mvc:mapping path="/user/*"/>
            <!--不要拦截的方法
            <mvc:exclude-mapping path=""/>
            -->
            <!--配置拦截器对象-->
            <bean class="cn.itcast.controller.cn.itcast.interceptor.MyInterceptor1" />
        </mvc:interceptor>

        <!--配置第二个拦截器-->
        <mvc:interceptor>
            <!--要拦截的具体的方法-->
            <mvc:mapping path="/**"/>
            <!--不要拦截的方法
            <mvc:exclude-mapping path=""/>
            -->
            <!--配置拦截器对象-->
            <bean class="cn.itcast.controller.cn.itcast.interceptor.MyInterceptor2" />
        </mvc:interceptor>
    </mvc:interceptors>

    <!-- 开启SpringMVC框架注解的支持 -->
    <mvc:annotation-driven />

</beans>
package cn.itcast.controller.cn.itcast.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 自定义拦截器
 */
public class MyInterceptor1 implements HandlerInterceptor{
    
    

    /**
     * 预处理,controller方法执行前
     * return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
     * return false不放行
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        System.out.println("MyInterceptor1执行了...前1111");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
        return true;
    }

    /**
     * 后处理方法,controller方法执行后,success.jsp执行之前
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
    
        System.out.println("MyInterceptor1执行了...后1111");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
    }

    /**
     * success.jsp页面执行后,该方法会执行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
    
        System.out.println("MyInterceptor1执行了...最后1111");
    }

}

2.10异常处理

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>cn.itcast</groupId>
  <artifactId>springmvc_day02_03_exception</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>springmvc_day02_03_exception Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <spring.version>5.0.2.RELEASE</spring.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>springmvc_day02_03_exception</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.7.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.20.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 开启注解扫描 -->
    <context:component-scan base-package="cn.itcast"/>

    <!-- 视图解析器对象 -->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--前端控制器,哪些静态资源不拦截-->
    <mvc:resources location="/css/" mapping="/css/**"/>
    <mvc:resources location="/images/" mapping="/images/**"/>
    <mvc:resources location="/js/" mapping="/js/**"/>

    <!--配置异常处理器-->
    <bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"/>

    <!-- 开启SpringMVC框架注解的支持 -->
    <mvc:annotation-driven />

</beans>
package cn.itcast.controller;

import cn.itcast.exception.SysException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/user")
public class UserController {
    
    


    @RequestMapping("/testException")
    public String testException() throws SysException{
    
    
        System.out.println("testException执行了...");

        try {
    
    
            // 模拟异常
            int a = 10/0;
        } catch (Exception e) {
    
    
            // 打印异常信息
            e.printStackTrace();
            // 抛出自定义异常信息
            throw new SysException("查询所有用户出现错误了...");
        }



        return "success";
    }

}

package cn.itcast.exception;

/**
 * 自定义异常类
 */
public class SysException extends Exception{
    
    

    // 存储提示信息的
    private String message;

    public String getMessage() {
    
    
        return message;
    }

    public void setMessage(String message) {
    
    
        this.message = message;
    }

    public SysException(String message) {
    
    
        this.message = message;
    }

}

package cn.itcast.exception;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 异常处理器
 */
public class SysExceptionResolver implements HandlerExceptionResolver{
    
    

    /**
     * 处理异常业务逻辑
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @return
     */
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    
    
        // 获取到异常对象
        SysException e = null;
        if(ex instanceof SysException){
    
    
            e = (SysException)ex;
        }else{
    
    
            e = new SysException("系统正在维护....");
        }
        // 创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg",e.getMessage());
        mv.setViewName("error");//跳到error.jsp页面
        return mv;
    }
}

2.11ssm整合

<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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.xsd
	http://www.springframework.org/schema/tx
	http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--开启注解的扫描,希望处理service和dao,controller不需要Spring框架去处理-->
    <context:component-scan base-package="cn.itcast" >
        <!--配置哪些注解不扫描-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

    <!--Spring整合MyBatis框架-->
    <!--配置连接池-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///ssm"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
    </bean>

    <!--配置SqlSessionFactory工厂-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!--配置AccountDao接口所在包-->
    <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="cn.itcast.dao"/>
    </bean>

    <!--配置Spring框架声明式事务管理-->
    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!--配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="*" isolation="DEFAULT"/>
        </tx:attributes>
    </tx:advice>

    <!--配置AOP增强-->
    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* cn.itcast.service.impl.*ServiceImpl.*(..))"/>
    </aop:config>

</beans>
<!DOCTYPE web-app PUBLIC 
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
<!--web.xml-->
<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <!--配置Spring的监听器,默认只加载WEB-INF目录下的applicationContext.xml配置文件-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!--设置配置文件的路径-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <context-param>
    <param-name/>
    <param-value/>
  </context-param>

  <!--配置前端控制器-->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--加载springmvc.xml配置文件-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!--启动服务器,创建该servlet-->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <!--解决中文乱码的过滤器-->
  <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>
  
</web-app>

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启注解扫描,只扫描Controller注解-->
    <context:component-scan base-package="cn.itcast">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

    <!--配置的视图解析器对象-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--过滤静态资源-->
    <mvc:resources location="/css/" mapping="/css/**" />
    <mvc:resources location="/images/" mapping="/images/**" />
    <mvc:resources location="/js/" mapping="/js/**" />

    <!--开启SpringMVC注解的支持-->
    <mvc:annotation-driven/>

</beans>
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=info, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n


package cn.itcast.controller;

import cn.itcast.domain.Account;
import cn.itcast.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * 帐户web
 */
@Controller
@RequestMapping("/account")
public class AccountController {
    
    

    @Autowired
    private AccountService accountService;

    @RequestMapping("/findAll")
    public String findAll(Model model){
    
    
        System.out.println("表现层:查询所有账户...");
        // 调用service的方法
        List<Account> list = accountService.findAll();
        model.addAttribute("list",list);
        return "list";
    }

    /**
     * 保存
     * @return
     */
    @RequestMapping("/save")
    public void save(Account account, HttpServletRequest request, HttpServletResponse response) throws IOException {
    
    
        accountService.saveAccount(account);
        response.sendRedirect(request.getContextPath()+"/account/findAll");
        return;
    }

}

package cn.itcast.dao;

import cn.itcast.domain.Account;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 帐户dao接口
 */
@Repository
public interface AccountDao {
    
    

    // 查询所有账户
    @Select("select * from account")
    public List<Account> findAll();

    // 保存帐户信息
    @Insert("insert into account (name,money) values (#{name},#{money})")
    public void saveAccount(Account account);

}

3ssm权限管理系统

3.1aop获取ip

在spring中,在web.xml中添加监听,可在代码中通过request获取访问ip

 <listener>
       <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
   </listener>
 @Autowired
    private HttpServletRequest request;
.....
    //获取访问的ip
    String ip = request.getRemoteAddr();

4springboot

4.1Springboot中的@Controller和@RestController的区别

@Controller类中的方法可以直接通过返回String跳转到jsp、ftl、html等模版页面。在方法上加@ResponseBody注解,也可以返回实体对象。
@RestController类中的所有方法只能返回String、Object、Json等实体对象,不能跳转到模版页面。@RestController相当于@ResponseBody + @Controller。
springboot项目启动时默认加载application.properties文件

4.2springboot配置文件多种注入方式

方式1:

@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig{
    
    
    @Value("${jdbc.url}")
    String url;
    @Value("${jdbc.driverClassNam}")
    String driverClassName;
    @Value("${jdbc.username}")
    String username;
    @Value("${jdbc.password}")
    String password;
    
    @Bean
    public DataSource dataSource(){
    
    
        DruidDataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
    
}

方式2:
首先将上一段代码中的注解@PropertySource(“classpath:jdbc.properties”)注释掉,然后在新建的配置类中添加@Data,会自动获取setget方法。其中使用时可以配置componet进行依赖注入,也可以在需要注入的类中使用注解@EnableConfigurationPropertie

@Configuration
@EnableConfigurationProperties
public class JdbcConfig{
    
    
  
    
    @Bean
    public DataSource dataSource(){
    
    
        DruidDataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
    
}
@ConfigurationProperties
@Data
public class JdbcProperties{
    
    
    String url;
    String driverClassName;
    String username;
    String password;
}

使用@EnableConfigurationPropertie注解后,在该类中也可以@Autowired注入该对象
方式3:

@Configuration
public class JdbcConfig{
    
    
  
    
    @Bean
    @ConfigurationProperties(prefix = "jdbc")//去配置文件找以jdbc开头的配置
    public DataSource dataSource(){
    
    
        return new DruidDataSource;
    }
    
}

##springboot自动加载application配置文件properties或者yaml

4.3日志级别配置是键值对形式的

loging:
  level: 
    cn.lyz:debug
    org.springframework:debug

4.4springboot自定义mvc配置拦截器记录日志

保持Springboot的一些默认mvc特征,同时自定义一些mvc配置(l拦截器、格式器、试图控制器、消息转换器等等),让一个类实现WebMVCConfigurer,并添加@Configuration注解,但是要去掉@EnableWebMvc注解。当自定义HandlerMapping、HandlerAdapter、ExceptionResolver等组件,x需要创建一个WebMvcRegistrationsAdapter实例来提供以上组件。

@Configuration
public class MvcConfig implements WebMvcConfigurer{
    
    
    public void addInterceptors(InterceotorRegistry regitry){
    
    
    registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
 }  
}//相当于将bean配置进去
@SLf4j
public class MyInterceptor implements HandlerInterceptor{
    
    
    //private static final Logger log = LoggerFactory.getLogger(MyInterceptor.class);等同于@SLf4j,相当于bean注入
    @Override
    public boolen preHandle...
}

4.5连接池

阿里连接池提供监控,但是速度不快
速度最快的是HikariCP(追光者.日本),spring默认支持它,不需要引入它的依赖,但是要引入spring默认的依赖spring-boot-starter-jdbc以及数据库驱动

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/数据库名
    username: root
    password: 123

单表的增删改查可以使用代码自动生成的sql
记得配置别名扫描包

mybatis:
  type-aliases-package: cn.lyz.dao

扫描mapper接口
@MapperScan(“cn.lyz.mapper”)
在启动类中配置此注解,会去相应路径下去扫描所有mapper接口

4.6mybatis

<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>2.0.3</version>
</dependency>

引用了tk.mybatis(mapper-spring-boot-starter)启动器(mybatis官方为springboot配置的启动器),则不需要引用(mybatis-spring-boot-starter)以及jdbc

在domain(pojo/dao)中标注数据库中的表名、id、以及相关表设置

@Data
@Table(name = "tb_user")//告诉程序报名是什么
public class User{
    
    
    @Id//告诉程序表的id是什么
    @KeySql(userGeneratedKeys = true)//告诉程序表的id是自增
    private Long id;
    private String userName;
    private String password;
    private String name;
    ...
    @Transient//在变量前加此注解,标识该变量不作为表的字段
    
}

Controller

@RestController
@RequestMapping("user")
public class HelloController{
    
    
    @Autowired
    private UserService userService;
    
    @@GetMapping("{id}")
    public User hello(@PathVariable("id") Long id){
    
    
        return userService.queryById(id);//使用mapping自己封装的方法
    }
}

5阿里微服务

如果在父工程中不使用,就是下载jar,并可以在子模块直接使用;而如果使用了就只是锁定版本而不下载jar,还需要在子模块另外添加依赖。

猜你喜欢

转载自blog.csdn.net/qq_39219307/article/details/114260483