当前位置: 首页 > news >正文

SSM学习

学习来源:黑马程序员

Spring Framework

在这里插入图片描述

核心容器

IOC控制反转——对象的创建控制权由程序转移到外部——解耦

实现思路:在Spring中提供了一个容器,称为IOC容器,用来充当IOC思想中的"外部",所以IOC容器中会包含大量的初始化对象,被创建或管理的对象在IOC中称为Bean

管理:service层,dao层,controller层,pojo层
通过配置管理:xml文件,注解
通过接口在Ioc容器中获取,并且使用接口方法得到相对应的Bean

//1.导入依赖spring-context
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.10.RELEASE</version></dependency>
</dependencies>//之后再resources文件夹下创建applicationContext.xml文件
//2.配置Bean  
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"><bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
</bean>//3.获取IOC容器_通过配置文件的方式    
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService"); //因为返回的是Object类型,所以需要强转  
userService.save();

DI依赖注入——在容器中建立Bean与Bean之间的依赖关系

因为其他层需要使用这个IOC容器中的初始化对象(BEAN)所以必须要声明,所以就实现的时候绑定好了关系

基于IOC管理bean:
service中不在使用new的方法创建Dao对象,通过配置文件得到相对应得关系

//配置dao与service的关系  
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
//property标签用于配置依赖关系,name属性用于的属性名称就是在Service类中定义的属性名称,ref属性用于指定注入的Bean的id  <property name="userDao" ref="userDao"></property>
</bean>

bean的别名

表示在其他层引用的时候可以自动注入,不只是ID也可以用别名注入 ,如果不存在会抛出名字不存在的异常

  <bean id="userDao" name="userDao2,userDao3" class="com.itheima.dao.impl.UserDaoImpl">
</bean>

其中Spring创建Bean给我们使用的时候是引用同一个地址的值,如果不想这样就可以使用scope属性默认是singleton,如果想要每次使用都创建新的对象就可以使用prototype

<bean id="userDao" name="userDao2,userDao3" class="com.itheima.dao.impl.UserDaoImpl" scope="prototype">
</bean>

bean实列化

1.构造方法
spring创建的时候调用的是无参的构建方法,但是可以调用私有方法——反射

2.使用静态工厂

public class UserDaoFactory{public static UserDao getUserDao(){return new UserDaoImpl();}
}
//需要告诉他使用那种方法——不直接new这个方法是因为可能这个工厂里面需要使用到  
<bean id="userDao" class="com.itheima.factory.UserDaoFactory" factory-method="getUserDao">
</bean>  

3.使用实例工厂
创建实列化工厂对象,然后使用实例化工厂对象创建对象

public class UserDaoFactory{public UserDao getUserDao(){return new UserDaoImpl();}
}//1.创建工厂对象
<bean id="userDaoFactory" class="com.itheima.factory.UserDaoFactory"></bean>//2.使用工厂对象创建对象——使用固定方法了
<bean id="userDao" factory-bean="userDaoFactory" factory-method="getUserDao">
</bean>

在这个基础上进行了改良,就是简化了代码,其中默认创建单例的。

public class UserDaoFactory implements FactoryBean<UserDao>{public UserDao getObject() throws Exception {return new UserDaoImpl();}public Class<?> getObjectType() {return UserDao.class;}   public boolean isSingleton() {return true;  //默认创建单例的}
}//配置文件中就可以  
<bean id="userDao" class="com.itheima.factory.UserDaoFactory"></bean>

bean的生命周期


public class UserDao{//初始化的操作public void init(){System.out.println("初始化");}
//销毁public void destroy(){System.out.println("销毁");}
}//为了使他对应所以在配置文件中需要配置  
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" init-method="init" destroy-method="destroy">

其中注意到销毁操作其实并没有直接执行,是因为JVM执行在虚拟机里面,当程序执行完了就直接关闭虚拟机了没有进行IOC容器的关闭
所以需要使用close方法,可以设置关闭钩子

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
context.registerShutdownHook();  //设置关闭钩子
//context.close()————暴力关闭  

后期改进后直接把配置放入定制里面了直接使用接口的放啊

public class Userpojo implements UserDao, InitializingBean, DisposableBean{public void afterPropertiesSet() throws Exception {System.out.println("初始化");//在属性设置完之后才执行,即set函数之后}public void destroy() throws Exception {System.out.println("销毁");}public void setBeanName(String name) {System.out.println("设置Bean名称");}}

流程为
创建对象(内存分配)——》执行构造函数——》执行属性注入(set操作)——》执行初始化方法(init)——》执行销毁方法(destroy)

依赖注入方式

1.setter注入:
简单类型:

public class BookDao implements BookDao{private int connectionNum;private String databaseName;public void setConnectionNum(int connectionNum) {this.connectionNum = connectionNum;}public void setDatabaseName(String databaseName) {this.databaseName = databaseName;}
}//配置文件中  
<bean id="bookDao" class="com.itheima.dao.impl.BookDao"><property name="connectionNum" value="10"></property><property name="databaseName" value="mysql"></property>
</bean>

引用类型:

<bean id="userDao" class="com.itheima.dao.impl.UserDao"></bean>
<bean id="bookDao" class="com.itheima.dao.impl.BookDao"></bean>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"><property name="bookDao" ref="bookDao"></property><property name="userDao" ref="userDao"></property>
</bean>
//在service方法中使用
public class UserServiceImpl implements UserService{private BookDao bookDao;private UserDao userDao;public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;}public void setUserDao(UserDao userDao) {this.userDao = userDao;}
}

2.构造器注入——标准书写

public class BookDao implements BookDao{private int connectionNum;private String databaseName;public BookDao(int connectionNum1, String databaseName) {this.connectionNum = connectionNum1;this.databaseName = databaseName;}
}
//配置中  
<bean id="bookDao" class="com.itheima.dao.impl.BookDao"><constructor-arg name="connectionNum1" value="10"></constructor-arg> //这里需要对应的是形参的值<constructor-arg name="databaseName" value="mysql"></constructor-arg>
</bean>

按照顺序写不按照名称写-解决与形参不耦合的问题_type

<bean id="bookDao" class="com.itheima.dao.impl.BookDao"><constructor-arg type="int" value="10"></constructor-arg> //这里需要对应的是形参的值<constructor-arg type="String" value="mysql"></constructor-arg>
</bean>

使用位置解决参数重复问题_index

<bean id="bookDao" class="com.itheima.dao.impl.BookDao"><constructor-arg index="0" value="10"></constructor-arg> <constructor-arg index="1" value="mysql"></constructor-arg>
</bean>

依赖自动装配

ICO容器会根据bean锁依赖的资源在容器内自动查找并注入到bean中的过程称为自动装配
自动装配方式
按类型、名称、构造方法、不启用自动装配

//在配置文件中中需要注意按类型装配的话就只能有一个的class不能重复  
<bean id="bookDao "  class="com.itheima.dao.impl.BookDao"/>
<bean id = "bookService" class="com.itheima.dao.impl.BookServiceImp" autowire="byType"/>//在服务中有bookDao和bookService的依赖,但是需要注意的是类型一致。byName是指按名称配置就必须要在里面对应上服务类和bean id向对应    
其中自动装配必须是类型依赖注入,不能对简单类型进行操作  

集合注入

数字

<beans .....>
<bean id="bookDao "  class="com.itheima.dao.impl.BookDao">
<propery name ="array1">
<array>
<value>100</value>
</array>
</propery><propery name ="list1"><list><value>100</value></list></propery><propery name ="set1"><set><value>100</value></set></propery></bean>
</beans>

数据源对象管理

对第三方Bean的管理

<dependency><groupId>com.alibaba</groupId><artifactId>druid<artifactId><version>1.1.16<version>
<dependency>//配置文件中,通过setter注入的方式
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/itheima"/><property name="username" value="root"/><property name="password" value="123456">
</bean>通过 
DataSource datasource = (DataSource) ctx.getBean("dataSource");

加载properties文件

读取到配置文件

<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
xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-beans.xsd"
">
把beans改成context就可以产生一个全新的context命名空间  使用context命名空间加载properties文件  
<context:property-placeholder location="jdbc.properties,jdbc2.properties" system-properties-mode="NEVER"/>  
//system-properties-mode="NEVER"这个表示不加载系统的环境变量不然会冲刷掉property里面,加载多个使用classpath*:*.properties,读取所有工程里面  classpath*表示读取所有的配置  
//就是利用一个新的配置文件去加载里面需要的<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}">
</bean>

容器

//通过文件系统加载配置文件  
ApplicationContext context = new FileSystemXmlApplicationContext("绝对路径");  //获取bean的实列,配置文件中的id\name  bookDao   
bookDao bookDao = context.getBean("bookDao",BookDao.class);//直接按照类型找,容器中该类型只能有一个  
bookDao bookDao2 = context.getBean(BookDao.class);

BeanFactory接口时最底层的接口、ApplicationContext是他的子接口
BeanFactory加载的Bean是延迟加载,而ApplicationContext加载的Bean是立即加载——可以在配置文件修改成为lazy-init="true"

注解开发

在类中添加@Component注解

@Component("userDao") //相当于在配置文件中写了<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
public class UserDaoImpl implements UserDao{}
//其中默认的时候就需要按类型去查找了,即在主函数中使用
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = context.getBean(UserDao.class);  //要按照类型去查找  //但是配置文件并不知道这个注解,所以还需要在配置文件中扫描,在context命名空间下   
<context:component-scan base-package="com.itheima.dao.impl"/>

其中@Component注解可以有多个,分别是@Controller控制层,@Service业务层,@Repository持久层

纯注解开发

因为配置文件中还需要配置扫描无法删除,此时就可以写一个类去替换他

@Configuration //表示这个类是一个配置类
@ComponentScan("com.itheima") //表示扫描com.itheima包下的所有注解,如果是多个可以添加数组的形式  
//@ComponentScan({"com.itheima","com.itheima2"})
public class SpringConfig{}//引用程序中也需要修改  
public class App{public static void main(String[] args){ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);//表示用注解开发,并且加载配置类    }
}

注解开发Bean管理

@Repository
@Scope("prototype") //表示创建的是多例的  
public class UserDaoImpl implements UserDao{@PostConstruct //初始化
public void init(){System.out.println("初始化");
}
@PreDestroy //销毁
public void destroy(){System.out.println("销毁");
}
}

自动装配

@Component //表示这个类是一个组件
@PropertySource({"classpath:jdbc.properties","classpath:jdbc2.properties"}) //表示加载配置文件,之后的简单类型引用需要使用,不允许使用通配符     
public class BookService{
@Autowired //按照类型注入,按照类型装配的,通过暴力反射,因此无需提供setter方法但是需要提供无参构造方法  
private BookDao bookDao;
}
//如果存在多个相同的Bean实现类,则需要使用@Qualifier("bookDao")来指定具体的Bean名称    @Value("${name}") //表示注入的简单类型注入——这个来自配置文件的    
private String name;

管理第三方Bean

@Configuration
@Import({jdbcSpringConfig.class,mybatisSpringConfig.class}) //表示导入一个配置类,可以导入多个配置类,也可以导入一个配置类
public class SpringConfig{}@Configuration
public class jdbcSpringConfig{@Bean //表示这个方法是一个Bean,返回值就是Bean的类型,方法的返回值就是Bean的类型,方法的参数就是Bean的依赖,不写就直接写类型  public DataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();//手写代码为了加载第三放beandataSource.setDriverClassName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/itheima");dataSource.setUsername("root");dataSource.setPassword("123456");return dataSource;}
}//在APP中  
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
DataSource dataSource = context.getBean(DataSource.class);//如果在第三方需要引用某些依赖注入需要在方法引参,会按照类型在Factrory工厂去查找 。    
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource){SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);return sqlSessionFactoryBean.getObject();
}

整合mybatis

<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.10</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>druid </artifactId><version>1.1.16</version>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.49</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.10.RELEASE</version>
</dependency>
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.0</version> //这个mybatis的提供为了是spring整合  
</dependency>//配置类
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")//读取配置文件里面的值
@Import({jdbcSpringConfig.class,mybatisSpringConfig.class})
public class SpringConfig{}//配置jdbc的配置 所以需要@PropertySource("classpath:jdbc.properties")public class jdbcSpringConfig{@Value("${jdbc.driver}")private String driver;@Value("${jdbc.url}")private String url;@Value("${jdbc.username}")private String username;@Value("${jdbc.password}")private String password;@Beanpublic DataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/itheima");dataSource.setUsername("root");dataSource.setPassword("123456");return dataSource;}}//配置mybatis的配置
public class mybatisSpringConfig{@Beanpublic SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource){SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);sqlSessionFactoryBean.setTypeAliasesPackage("com.itheima.pojo");//类型别名的包,就是mybatis返回的实体类在那个包下面。  return sqlSessionFactoryBean.getObject();}@Bean public MapperScannerConfigurer mapperScannerConfigurer(){MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();mapperScannerConfigurer.setBasePackage("com.itheima.dao");//表示调用的抽象方法mapper的    return mapperScannerConfigurer;}
}

Junit整合

<dependency><groupId>junit</groupId><artifactId>junit </artifactId><version>4.13.2</version><scope>test</scope>
</dependency>
//junit5需要使用junit-jupiter
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.10.RELEASE</version>
</dependency>//junit测试整合spring
@RunWith(SpringJUnit4ClassRunner.class) //表示使用spring的测试框架
@ContextConfiguration(classes = {SpringConfig.class}) //表示加载的配置类
public class UserDaoTest{@Autowiredprivate UserService userService;@Testpublic void test(){userService.save();}
}

AOP

AOP是面向切面编程,是一种编程范式,提供从另一个角度考虑程序结构以完善面向对象编程(OOP)。
作用:在不惊动原始设计的基础上对程序进行功能增强。
思想:无侵入式编程,无入侵式编程
每个方法称为连接点,而需要追加功能的方法称为切入点,共性的功能称为通知,通知和切入点之间靠切面连接在一起,通知类就是用来通知的

入门案列

在接口执行器输出当前系统事件
1.导入依赖
2.制作连接点
3.制作共性
4.制作切入点
5.制作切面

<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId>  //在context包里面<version>5.2.10.RELEASE</version>
</dependency>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.7</version>
</dependency>//创建通知类
@Component   //变成Spirng控制的bean
@Aspect      //变成切面类——特殊的类  
public class MyAspect{@Pointcut("execution(void  com.itheima.service.UserService.save())")public void pt(){}@Before("pt()")   //表示在这个方法之前执行  public void method(){System.out.println("环绕通知");}}//还需要再配置文件中添加
@EnableAspectJAutoProxy //表示开启AspectJ自动代理,因为原本不知道是拿注解开发的  

AOP工作流程

1.启动
2.读取所有切面配置的切入点,只读取配置的。
3.初始化容器,判定bean对应的方法是否匹配到任意切入点
失败创建原始对象
匹配成功,创建原始对象的代理对象
4.获取bean执行方法
获取bean的代理对象执行方法 ——实现代理完成

代理对象:就是新创建出来的“替身对象”,不是你原本写的那个对象,但它“长得像”、“行为像”,并且可以替代原对象完成任务,还能加点“私货”(增强功能,比如事务、日志等)

切入点表达式

@Pointcut注解中使用
可以按照实现类、接口的描述方法如

execution(privatevoid com.itheima.service.UserService.save())
execution(void com.itheima.service.UserServiceImpl.save()) //默认public  

切入点表达式的标准格式:动作关键字(访问修饰词 返回值 包名.类名.方法名(参数) 异常)
异常可以省略

可以使用通配符

  • 表示任意至少一个
    … 表示任意多个
  • 专用于匹配子类型
    如:
    execution(* com.itheima.service.UserService.save*(..))
    execution(* com.itheima.service.*Service+.*(..)) 匹配业务层的所有方法

通知类型

前置通知:在方法执行之前执行——@Before
后置通知:在方法执行之后执行始终执行——@After

环绕通知:在方法执行之前和之后执行——@Around
必须得存在一个ProceedingJoinPoint参数,表示对原始操作方法的执行——对原始数据进行隔离的操作

@Around("pt()")
public void method(ProceedingJoinPoint pjp)throws Throwable{ //不用处理异常,只是增强作用System.out.println("环绕通知前");pjp.proceed();System.out.println("环绕通知后");
}//需要注意的是必须要返回值,因为不能把返回值经过这个处理后消失了,所以这么写  
public Object method(ProceedingJoinPoint pjp)throws Throwable{System.out.println("环绕通知前");Object proceed = pjp.proceed();//代理模式,执行原始方法,有加有返回  System.out.println("环绕通知后");return proceed;
}

其中ProceedingJoinPoint pjp是Spring提供的一个接口,表示对原始操作方法的执行,可以获取原始方法的参数,返回值,方法名,方法类型等信息
就比如果使用pjp.getSignature() 就可以获得签名信息
pjp.getArgs() 可以获得原始方法的参数即传来的参数使用一个Object[]数组接受
pjp.proceed() 可以执行原始方法,可以使用pjp.proceed(args) 来执行原始方法,其中args是就可以对其中的参数修改

Signature signature = pjp.getSignature(); 
String className = signature.getDeclaringTypeName(); //获得执行类型(接口)名   
String name = signature.getName();  //获得方法名  

异常通知:在方法执行过程中抛出异常时执行,不出异常不执行——@AfterThrowing

@AfterThrowing(value = "pt()",throwing = "e")  //这里的e表示的就是异常
public void method(JoinPoint joinPoint,Exception e){System.out.println("异常通知");System.out.println(e);
} //添加异常  

最终通知:在方法正常执行结束之后执行,如果抛异常了就不执行——@AfterReturning

@AfterReturning(value = "pt()",returning = "result")  //这里的result表示的就是返回值
public void method(JoinPoint joinPoint,Object result){//规定了joinpoin必须放第一个 后面的表示的是函数执行完后的结果进行操作System.out.println("最终通知");System.out.println(result);
}

事务

保障数据层/业务层一系列的数据库操作同成功/失败

publi interface PlatformTransactionManager{void commit(TransactionStatus status) throws TransactionException;void rollback(TransactionStatus status) throws TransactionException;
}

利用jdbc的事务实现的
模拟转账业务A减钱B加钱

//如果添加在类上,表示这个类中所有方法都添加事务
@Transactional //表示这个接口是一个事务,开启的地方是在接口上而不是实现类上  
public interface AccountDao{@Update("update account set money = money - #{money} where id = #{id}")void outMoney(@Param("id") int id,@Param("money") int money);@Update("update account set money = money + #{money} where id = #{id}")void inMoney(@Param("id") int id,@Param("money") int money);
}//在配置文件配置需要声明一个事务管理器  
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){return new DataSourceTransactionManager(dataSource);//本质上还是利用JDBC的事务  
}//在主配置文件中需要扫描一下事务管理
@EnableTransactionManagement //表示开启事务管理

相当于在方法内的另外的事务添加到spring事务中,这样就把几个事务变成一个事务,从而实现回滚等效果
所以需要在配置文件中声明一下应该是同一个数据库的数据源,才能实现事务

事务相关配置

可以通过注解修改事务属性
@Transactional(,rollbackFor = {IOException.class,SQLException.class})
表示事务遇到了IOException和SQLException时回滚,有些异常是不参与回滚的

事务的传播行为

事务协调员对事务管理员所携带的处理态度
@Transactional(propagation = Propagation.REQUIRED)
表示单独新开启一个事务,即不参与事务管理员的事务
REQUIRES表示如果事务管理员有事务哪么协调员加入
REQUIRES_NEW表示如果事务管理员有事务哪么协调员新开启一个事务,即不参与事务管理员的事务
SUPPORTS表示如果事务管理员有事务哪么协调员加入,没有事务哪么协调员不开启事务
NOT_SUPPORTED始终不开启事务
MANDATORY表示如果事务管理员有事务哪么协调员加入,没有事务哪么协调员抛出异常
NESTED表示如果事务管理员有事务哪么报错,没有事务哪么协调员新开启一个事务,那么没关系

Spring MVC

springMVC技术与Servlet技术类似,都是基于MVC设计模式,但是springMVC比Servlet技术更加简单,更加易用,更加高效。

@RequestMapping("/save")
@ResponseBody  
public String save(){return "success";
}

简介

Spring MVC是一个基于Java的Web框架,用于构建Web应用程序。它提供了一种简单、灵活且可扩展的方式来处理Web请求和响应。Spring MVC的核心组件包括:

//导入依赖  
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.10.RELEASE</version>
</dependency>//添加tomcat插件  
<bulid><plugins><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version></plugin></plugins>
</bulid>
//创建成为控制类BEAN注入  
@Controller
public class UserController{@RequestMapping("/save")@ResponseBody     public String save(){return "success";}
}//SPring Mvc控制类  
@Configuration
@ComponentScan("com.itheima")
public class SpringMvcConfig{}//tomcat启动的时候会启动这个类  
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer{protected WebApplicationContext createServletApplicationContext(){AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();ctx.register(SpringMvcConfig.class);return ctx;}//告诉tomcat容器加载SpringMvcConfig的配置容器  protected String[] getServletMappings(){return new String[]{"/"};}//告诉tomcat容器,/的请求都由SpringMvc容器处理  protected WebApplicationContext createRootApplicationContext(){return null;} //加载SPRING 容器的配置  
}

流程
初始化:
1.服务器初始化——通过ServletContainersInitConfig类初始化
2.加载WebApplicationContext方法创建对象
3.加载SpringMvcConfig配置类,创建SpringMvc容器
4.加载容器内对应的bean和每个@RequestMapping注解的控制器
5.执行getServletMapping方法,定义所有请求通过SpringMvc容器处理
单次请求过程:
1.发送请求localhost:8080/save
2.web容器发现所有请求都经过SpringMvc容器处理
3.解析请求路径
4.执行控制器中的方法
5.执行方法的返回值放入响应体返回给浏览器

springmvc 只加载他所对应的包(表现层的的包,controller)
spring 回加载业务bean 和功能bean ,所以如何避免springmvc加载到springmvc已经加载的controller
解决办法:扫描包的时候具体扫描@componentScan("")/全部扫描指定某个包不扫描@ComponentScan(excludeFilters = @Filter(type = FilterType.ANNOTATION,classes = {Controller.class})type后面表示按照注解过滤

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer{@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[]{SpringConfig.class};}@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[]{SpringMvcConfig.class};}@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}
}
//和上面写servlet配置一样的

请求与响应

请求路径前缀:@RequestMapping("/book")
请求方式:
如果请求为localhost:8080/book/save?name=itheima&age=20

@RequestMapping("save")
@ResponseBody
public String save(String name,int age){System.out.println(name);System.out.println(age);return "success";
}

发送表单数据x-www-form-urlencodedPost请求

@RequestMapping(value = "/save",method = RequestMethod.POST)
@ResponseBody
public String save(String name,int age){System.out.println(name);System.out.println(age);return "success";
}

乱码处理,用过滤器在配置文件中添加

@Override
protected Filter[] getServletFilters(){CharacterEncodingFilter filter = new CharacterEncodingFilter();filter.setEncoding("UTF-8");return new Filter[]{filter};//多个过滤器可以往后面写  
}

各种各样参数传递

如果消息之间传递的名称不同,会无法映射了如果不同需要使用@RequestParam注解,如果不写就是使用形参名

@RequestMapping("/save")
@ResponseBody
public String save(@RequestParam("name") String username,@RequestParam("age") int userage){System.out.println(username);System.out.println(userage);return "success";
}

直接使用实体类去接受对应的属性-自动接受并且对应
数组传参数的都是一样的

Json数据

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.13.0</version>
</dependency>

Postman 发送JSON数据

集合接受JSON数据,开启功能键开启JSON转化为对象等功能

@EnableWebMvc
@Configuration
@ComponentScan("com.itheima")
public class SpringMvcConfig{}//将接受数据转化为对象
@RequestMapping("/save")
@ResponseBody
//使用@RequestBody注解将JSON数据转化为对象  
public String save(@RequestBody User user){System.out.println(user);return "success";
}

日期类型参数传递

前端传来的为2025-04-25 默认格式

@RequestMapping("/save")
@ResponseBody
public String save(Date date){System.out.println(date);return "success";
}

使用@DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss") Date date注解将日期类型转化为字符串
利用的是 Converter 类型转换器

public interface Converter<S,T> {@NullableT convert( S source);//将传递的参数转化为需要的类型,是个接口实现类有很多
}

@EnableWebMvc就是开启这个功能的其他转化功能,使用默认的可能有些无法转化

响应

如果不添加@ResponseBody注解就会返回的就是一个跳转的页面如

@RequestMapping("/save")
public String save(){return "page.jsp";
}

如果添加了@ResponseBody注解,返回的就是一个json数据,激活的类型转化使用的是httpMessageConverter,转化http消息

@RequestMapping("/save")
@ResponseBody
public String save(){return "success";
}

REST风格

定义:表现新式状态转化
优点:
1.隐藏资源的访问路径
2.书写简单
3.安全
4.对搜索引擎友好

通过行为区分对资源进行何种操作即:
1.GET 获取资源
2.POST 新建资源
3.PUT 更新资源
4.DELETE 删除资源

风格:只是一种约定方式,不是规范,所以可以打破,模块的名称统称为复数,也就是加S的格式描述

//从而限定了提交方式
@RequestMapping("/users/{username}",method = RequestMethod.POST)
@ResponseBody
public String save(@PathVariable String username){return "success";
}@RequestMapping("/users",method = RequestMethod.POST)
@ResponseBody
public String save(@RequestBody String username){return "success";
}

快速开发

@Controller
@ResponseBody//全部的返回值都变成JSON类型的http响应体这两个合并称为RestController@RestController
@RequestMapping("/user")
public class UserController{@PostMapping("/{username}")public String save(@PathVariable String username){return username;  }
}

放行非SpringMVC的请求
当访问某个页面的时候也会被拦截器拦截,即被SPRINGMVC 拦截了,所以配置文件中应该修改
设置一个功能配置

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport{@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry){registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");}
//访问/pages/xxx 的时候不要去走Mvc的请求,而是走/page目录下的内容 
}配置好了需要在总配置文件中加载这个——扫描进去@ComponentScan("com.itheima")

SSM整合

整合SSM

流程:
配置类
Spring -spirngconfig
Mybatis -mybatisconfig
-JdcnConfig
-jdnc.properties
SpringMVC -springmvcconfig
-springmvc.xml
功能模块
表与实体类
dao接口+自动代理
service接口+自动代理整合JUnit测试
Controller层——请求与相应测试

表现层封装

因为传来的数据太多种类了,所以选择新创建一个类用来封装类——date
但是不知道是什么操作,所以采用code属性去定义
但是用户不知道是什么操作,所以采用message(msg)属性去定义
所以写在表现层Controller中

public class Result{private Integer code;private String msg;private Object data;
//需要构造方法  
public Result(Integer code,String msg,Object data){this.code = code;this.msg = msg;this.data = data;
}}
再定义一个类型去封装CODE的类型  

public class ResultCode{
public static final Integer SUCCESS = 200;
public static final Integer ERR = 500;
}

之后在bookController中使用

public Result save(){boolean flag = true;return new Result(flag? ResultCode.SUCCESS:ResultCode.ERR,"success",null);}

异常处理器

所有异常均抛到表现层进行,表现层处理异常中的每个方法单独书写,代码书写量大且意义不大——AOP解决

异常处理器:可以集中的、同理的处理项目出现的异常——写在表现层

@RestControllerAdvice //全局异常处理器统一拦截 Controller,但不负责返回 JSON
public class ProjectExceptionAdvice{@ExceptionHandler(Exception.class) //指定处理的异常类型public Result doException(Exception ex){return new Result(ResultCode.ERR,"error",null);}
}

异常分类:
业务异常:规范的用户行为产生的异常,不规范的用户行为操作异常
解决办法:反馈消息给用户
系统异常:项目运行过程中可预计且无法避免的异常
解决办法:记录日志,反馈消息给用户,并且给特定消息给运维人员
其他异常:编程人员无法预见的异常
解决办法:记录日志,反馈消息给用户,并且给特定消息给运维人员

所以需要定义一个异常文件夹里面记录不同的异常类

public class BusinessException extends Exception{private Integer code;public BusinessException(Integer code,String message,Throwable cause){super(message,cause); //使用父类的异常消息并且把异常封住起来      this.code = code;}
}

将可能出现的异常需要进行包装称为一个新的异常,一般在业务层的异常进行包装

public Book getBookById(Integer id){try{int i = 1/0;}catch(Exception e){throw new BusinessException(ResultCode.ERR,"图书不存在",e);}return null;
}

拦截器

在这里插入图片描述

定义:是一种动态拦截方法调用的机制,在springMVC中动态拦截控制器方法的执行
作用:
1.在指定的方法调用前后执行预先设定的代码
2.阻止原始方法执行

拦截器和过滤器的区别:
1.拦截器是springMVC中提供的一种机制,过滤器是Servlet中提供的一种机制
2.过滤是对所有请求进行拦截,拦截器只拦截控制器方法

拦截器定义的功能类,放在controller文件中interceptor文件夹下, 并且需要需要扫描到

@Component
public class ProjectInterceptor implements HandlerInterceptor{//在控制器方法执行之前执行@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;//如果是false表示中止原始操作,后面的操作方法就不执行了,其实是跳过了这个方法  }//在控制器方法执行之后执行@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {//ModelAndView,表示的是页面跳转的地方  }@Override  //在拦截之后的方法并且在PostHandle之后执行,主要是用来处理异常的但是现在有异常处理器   public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}//给springmvc配置文件中添加拦截器  
@Configuration 
public class SpringMvcSupport extends WebMvcConfigurationSupport{@Autowiredprivate ProjectInterceptor projectInterceptor;//配置静态资源@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");} //访问某个路径的配置静态资源@Overrideprotected void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");// 表示访问那个路径的时候需要去拦截,其中路径必须是具体的  }
}
//或者直接在总配置中配置  
@Configuration
@ComponentScan("com.itheima")
@EnableWebMvc //开启JSON转化器  
public class SpringMvcConfig{@Autowiredprivate ProjectInterceptor projectInterceptor;//配置静态资源@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");} //访问某个路径的配置静态资源@Overrideprotected void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");// 表示访问那个路径的时候需要去拦截,其中路径必须是具体的  registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");  //表示配置两个拦截器,顺序只和现在的顺序有关}
}

拦截参数

@Component
public class ProjectInterceptor implements HandlerInterceptor{@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//其中handler是对调用的处理器对象,本质上是一个方法对象,对反射技术的Method类对象再次进行封装,就是反映出是那个类中的方法调用了这个拦截器,可以实现对方法的动态修改。  //获取方法的名称  String methodName = ((HandlerMethod) handler).getMethod().getName();System.out.println("拦截器拦截了方法:" + methodName);request.setAttribute("msg","拦截器拦截");}
}

多拦截器

顺序和配置文件中配置的顺序有关
在这里插入图片描述

Maven

分模块开发

依赖其他模块中的资源——从本地的 Mavenc仓库

<dependencies><dependency><groupId>com.itheima</groupId><version>1.0-SNAPSHOT</version><artifactId>ssm</artifactId></dependency>
</dependencies>

所以需要将ssm模块通过maven的install命令安装到本地仓库中

依赖管理

依赖的传递性——当前的依赖可能依赖别的东西
直接依赖:在当前的pom.xml中配置的依赖
间接依赖:被资源的资源如果依赖其他的资源就是当前项目的间接依赖

依赖之间的冲突:
当依赖中同一个坐标配置多次,以最后一次为准——后配置覆盖先配置的
路劲优先:当依赖出现相同的资源时候,层级越深,优先级越低,层级越浅,优先级越高
声明优先:当资源在相同层级被依赖时,配置顺寻靠前的覆盖配置顺序靠后的——在依赖的维度上。

可选依赖与排除依赖:
可选依赖:隐藏当前资源可依赖的资源,隐藏后对应资源不具有依赖性,就是不想让别人也使用这个依赖——不透明

<dependency><groupId>com.itheima</groupId><artifactId>ssm</artifactId><version>1.0-SNAPSHOT</version><optional>true</optional>//true表示隐藏  
</dependency>

排除依赖:某个工程中已经带有依赖了,但是不想使用这个依赖需要排除掉,那么就需要使用排除依赖 ——不需要

<dependency><groupId>com.itheima</groupId><artifactId>ssm</artifactId><exclusions><exclusion><groupId>org.springframework</groupId><artifactId>spring-context</artifactId></exclusion> //表示排除的依赖,隐藏当前资源对应的依赖</exclusions>
</dependency>

聚合和继承

聚合

聚合:多个模块组织成一个整体,同时进行项目构建的过程称为聚合
聚合工程:通常是一个不具有业务功能的“空”工程,只用于组织模块,进行项目构建

用来做工程管理的打包方式为pom

<groupId>com.itheima</groupId>
<artifactId>ssm</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>//设置管理模块  
<modules><module>../ssm-dao</module><module>../ssm-service</module><module>../ssm-controller</module>
</modules>

在使用complie会自动编译管理模块,会依赖关系进行构造

继承

继承:子工程可以继承父工程的依赖配置
作用:简化依赖配置,实现依赖传递

//继承上面的聚合工程
<parent><groupId>com.itheima</groupId><artifactId>ssm</artifactId><version>1.0-SNAPSHOT</version><relativePath>../pom.xml</relativePath>
</parent><dependencyManagement><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId></dependency></dependencies>
</dependencyManagement>  //这个表示的是选择使用如果子工程想要使用就必须在里面声明//子工程需要使用的时候需要声明
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId></dependency>
</dependencies> //不需要添加版本号  

属性管理

属性能够定义一个名称,从而能达到改一个就是改全部

<properties> //这个就是属性  <spring.version>5.2.10.RELEASE</spring.version> //属性名称 <jdbc.url>jdbc:mysql://localhost:3306/ssm</jdbc.url> //属性值——但是这个只能在pom文件中读取不能在配置文件中读取,所以需要扩大范围  
</porperties>//其他地方书写为
<version>${spring.version}</version>//配置build表示某些资源文件也可以使用这个属性这个可以在任意的pom文件中使用都会成功加载       
<build><resources><resource><directory>${project.basedir}/src/main/resources</directory>//给出需要使用的目录  <filtering>true</filtering> //表示是否使用属性_开启过滤规则    </resource></resources>  //可以直接打开文件了相当于在maven的时候就会直接把值写到对应的地方     
</build>  //其中里面的${project.basedir}表示maven自己内置的属性  

其他属性
${自定义属性名称}
${内置属性名称}
${Setting.属性名称}
${系统属性分类.系统属性名} /${user.home}
${env.环境变量属性名称}

版本管理

maven的工程版本:
SNAPSHOT(快照版本)——正在开发
项目开发过程中临时输出的版本,称为快照版本
快照版本会随着开发的进展不断更新
RELESASE(发布版本)——稳定版本
项目开发到进入阶段后相对稳定的版本

发布版本
alpha版
beta版
纯数字版

多环境配置与应用

配置多环境

<profiles><profile><id>env_dep</id>//设置专用属性  <properties><jdbc.url>jdbc:mysql://localhost:3306/ssm</jdbc.url></properties><activation><activeByDefault>true</activeByDefault> //表示默认激活,为默认环境  </activation></profile><profile><id>env_test</id>//设置专用属性  <properties><jdbc.url>jdbc:mysql://localhost:3306/ssm_ab</jdbc.url></properties></profile>
</profiles>

之后
maven install -P env_test //表示执行test环境

跳过测试:
存在功能更新中并且没有开发完毕。
快速打包
maven install -D skip TEST
测试使用的是一个插件

<build><plugins><plugin><artifactId>maven-surefire-plugin</artifactId><version>2.12.4</version><configuration><skipTests>false</skipTests> //表示是否跳过测试//排除掉不参与测试的内容  <excludes><exclude>**/Test*.java</exclude>//表示排除掉Test开头的测试类</excludes></configuration></plugin></plugins>
</build>

私服

介绍:一台独立的服务器,用于解决团队内部的资源共享与同步问题
Nexus:一个私服的软件,可以实现资源的共享与同步
https://help.sonatype.com/repomanager3/download地址
进入nexus-3.30.1-1-bin下进入cmd启动这个私服nexnus.exe/run nexus
进入8081端口,可以在etc/nexus-default.properties中修改

私服中可以创建多个仓库,其中有一个仓库是可以直接和中央服务器打交道的,这样就断绝了自己主机和中央服务器的直接联系。
还可以更具环境设置不同的仓库中——仓库管理太麻烦了,所以设置了仓库组(多个仓库合成一个)
宿主仓库-host-保存自主研发+第三方资源-上传
代理仓库-proxy-保存远程中央仓库的资源-下载
仓库组-group-将宿主仓库和代理仓库进行组合-下载

资源上传与下载
在这里插入图片描述

去maven的config文件夹下的settings.xml中配置私服

//本地仓库对私服的访问权限
<server><id>nexus-releases</id>  //表示私服的id<username>admin</username><password>admin123</password>
</server><mirrors> //配置私服的访问路径 <mirror><id>nexus</id> //仓库组的id<url>http://localhost:8081/repository/maven-public/</url> //选择地址  <mirrorOf>*</mirrorOf></mirror>
</mirrors>

私服的上传与下载

在pom文件中配置私服的访问路径

<distributionManagement><repository>//表示配置的是正式版本配置的仓库<id>nexus-releases</id><url>http://localhost:8081/repository/maven-releases/</url></repository><snapshotRepository>//表示配置的是快照版本配置的仓库  <id>nexus-snapshots</id><url>http://localhost:8081/repository/maven-snapshots/</url></snapshotRepository>
</distributionManagement>

maven deploy //表示上传到私服-私服会自动下载大量资源

SpringBoot

定义:是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程

springboot已经自动内置了一个tomcat,因为直接继承了maven中的spring-boot-starter-web依赖

<parent>  //表示继承springboot的父工程<groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.14.RELEASE</version>
</parent>

只需要pom.xml和application文件
需要maven package打包

<build><plugins><plugin>//就是利用了这个插件,不仅打包了要用的jar包,还包含了其他jar包  <groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins>
</build>

boot程序可以直接传递一个jar包就可以使用了,不需要再次安装tomcat等web工具
java -jar 文件名.jar

因为springboot的父pom中已经将所有的版本号都已经配置好了,只需要引用依赖就会自动匹配相应的版本号,starter表示启动依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>  

所以spring-boot-starter-web依赖中已经包含了spring-boot-starter-tomcat,所以不需要再次配置tomcat
不想用某个技术的时候可以直接使用exclude排除掉,而不能使用可选因为父pom中的只是可读

基础配置

修改配置文件在resources文件夹下创建application.properties文件

server.port=80 //表示修改端口号    

更规范的为application.yml文件

server:port: 80  //数字前面一定要有空格  
logging:level:root: info //表示修改日志级别      

如果需要配置多个配置文件中,properties先生效,然后是yml最后为yaml

yaml文件

是一种数据序列化格式,阅读性好,书写简单,比json更简洁,比xml更直观
语法格式:
大小写敏感
使用缩进表示层级关系
缩进时不允许使用Tab键,只允许使用空格
缩进的空格数不重要,只要相同层级的元素左侧对齐即可
数组格式:

likes:  - java  - python  - c++  

使用配置文件中的数据
@Value("${配置文件中的key}")就可以读取到了

@Autowired
private Environment env; //表示读取配置文件中的所有数据,使用环境对象进行封装  //使用自定义对象去封装  
@Component
@ConfigurationProperties(prefix = "user") //从配置文件中的顶层中算  
public class User {private String name;private Integer age;
}//可能用自定义对象封装会出现数据警告——消除警告    
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional>  
</dependency>

多环境开发

//application.yml   
spring:profiles: active: dev  //设置开启时候的默认环境    ---
spring:profiles: dev
server:port: 80---
spring:profiles: test
server:port: 8080---
spring:profiles: prod
server:port: 8081

通过命令启动去切换环境
java -jar 文件名.jar --spring.profiles.active=dev//表示带参数启动springboot,继续带参数去修改配置文件
java -jar 文件名.jar --server.port=88 --spring.profiles.active=test
要使用maven中的配置文件去定义springboot中的参数从而实现相关联,但是还需要一个插件使这两个相互关联起来,springboot听从maven的设置

<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.5.14.RELEASE</version><configuration><enconding>UTF-8</enconding><useDefaultProfiles>true</useDefaultProfiles> //表示使用默认的配置文件   </configuration></plugin></plugins>
</build>

就是如果使用application.yml文件中配置的可以替代jar包中的application的文件,这样就可以实现环境更改了,而如果在jar包的文件夹下设置一个config目录,并且给出相应的yml文件这个优先级更高

在这里插入图片描述

整合第三方技术

springboot整合JUnit

//SpringBoot中的一开始启动的Application类,就是启动类,他会把当前类和他的子类的所有文件都扫描一次,所以测试类也需要在同层下或者使用@SpringBootTest(classes = Application.class) //表示启动springboot测试整合了unit的运行器,并且加载的配置文件也整合了
class SpringbootTest {@Autowiredprivate User user;@Testpublic void testUser() {System.out.println(user);}
}

配置文件连接的数据库,需要在yml里面声明

spring:datasource:type: com.alibaba.druid.pool.DruidDataSource //数据源对象url: jdbc:mysql://localhost:3306/ssm?useUnicode=true&driver-class-name: com.mysql.cj.jdbc.Driver  username: rootpassword: 123456

添加
@Mapper这个注解就是用来创建代理类——对接口使用

页面放在resources/static文件夹下

相关文章:

  • LibAI Lab走进西浦:重塑“AI+建筑”教育
  • C语言之操作符
  • 从 PID 到 Agent:工业控制算法的五代进化史与智能协同革命
  • 哪些因素会影响远程视频监控的质量?浅述EasyCVR视频智能诊断技术
  • 手动创建一份konga对应helm的chart项目
  • 【学习笔记】机器学习(Machine Learning) | 第五章(1)| 分类与逻辑回归
  • 浅谈C# record关键字
  • DeepSeek谈《凤凰项目 一个IT运维的传奇故事》
  • 蛋白质数据库UniProt介绍
  • git中reset和checkout的用法
  • Webug4.0通关笔记06- 第8关CSV注入
  • 文件读取操作
  • 【论文速读】《Scaling Scaling Laws with Board Games》
  • 数据结构学习篇——哈希
  • 冰冰一号教程网--介绍采用vuepress搭建个人博客
  • Git 忽略文件配置 .gitignore
  • 客户服务升级:智能语音外呼系统在多领域的场景应用解析
  • navicat中导出数据表结构并在word更改为三线表(适用于navicat导不出doc)
  • rails 创建数据库表
  • java实现序列化与反序列化
  • “80后”商洛市委副书记、市政府党组副书记赵孝任商洛市副市长
  • 【社论】法治是对民营经济最好的促进
  • 上海国际咖啡文化节开幕,北外滩集结了超350个展位
  • 人民日报:在大有可为的时代大有作为
  • 光明日报:回应辅警“转正”呼声,是一门政民互动公开课
  • 浙商银行外部监事高强无法履职:已被查,曾任建行浙江省分行行长