try catch快捷键
ctrl+alt+t
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
:设置注解的作用范围
@RequestParam
注解:进行请求参数的映射配置
@ResponseBody
注解:用来表示将控制器方法的返回值直接作为响应的响应体的内容发送给客户端
@RequestMapping("view01")
注解:配置响应的地址
@ResponseBody
注解:将一个JAVA对象转成JSON【从服务器到客户端】
@RequestBody
注解:将一个JSON串转换成JAVA对象【从客户端到服务器】
@RestController
注解: 等于@ResponseBody
+@Controller
作用范围:所有的处理方法
@JsonFormat(pattern = "yyyy-MM-dd")
注解:配置日期转换的具体格式,配在属性上
@Import({Red.class, Blue.class, Green.class})
注解:进行组件的批量注册
@Conditional
包括衍生注解进行组件的条件注册【出现在springboot的源码中 了解】
@Configuration
@PropertySource("classpath:druid.properties")
注解:
@EnableAspectJAutoProxy
注解:开启AOP的注解支持
@SpringBootApplication
注解:该注解是一个复合注解,由三个注解组成@SpringBootConfiguration:和@Configuration的作用一样,表示当前类是一个配置类 @EnableAutoConfiguration:开启SpringBoot的自动配置 @ComponentScan:用来配置组件扫描
@EnableAutoConfiguration
注解:该注解也是一个复合注解,由两个注解组成@AutoConfigurationPackage:自动配置要扫描的包 @Import(AutoConfigurationPackages.Registrar.class)
将该类型的对象配置到IOC容器:
@Component
注解:【相当于是xml中的bean标签的作用】
【@Controller
页面层组件@Service
业务层@Repository
持久层】来替代@Component
属性注入
@Value("${jdbc.driver}")
简单类型
@Autowired
:按类型自动注入【后期使用最多的一个依赖注入注解】
@Qualifier("userDaoImpl1")
按照byName的方式进行自动的依赖注入
@Resource
:该注解是由jdk提供的,被Spring框架支持
采用配置的方式【避免编写控制方法进行请求转发】<mvc:view-controller path="/user_add" view-name="user_add"/>
是目前非常流行的项目管理工具,同类产品还有 Gradle
官网:http://maven.apache.org/
1.项目构建 :IDEA的这一套项目管理的流程只能在本地完成,完成项目代码的编译、测试、打包和部署
2.依赖管理:管理Jar及其下载,版本,Maven获取JAR包的方式:私服,本地仓库,镜像仓库,中央仓库
聚合工程:通过一个父工程去集中的管理一些子工程
是一个基于Java的持久层框架,
官网地址:https://github.com/mybatis/mybatis-3
实现从应用程序到数据的访问,它是对JDBC的操作进行了封装,
将sql语句从JAVA代码中分离到一个专门的映射配置【.xml 注解】中,更易于软件项目的维护
mybatis的查询缓存,提升程序的执行效率
mybatis的分页插件
mybatis的核心配置文件,文件名为mybatis-config.xml【约定俗成】
mybatis依赖一个开源的日志框架log4j
进行日志的输出
注意:配置文件的名称必须叫log4j.properties[log4j.xml]
1.引入相关的依赖
2.按照映射关系创建实体类Employee
3.创建mybatis的核心配置文件,文件名为mybatis-config.xml【约定俗成】
4.创建数据访问接口,接口的命名规范:表名+Mapper.java,一张表对应一个Mapper接口
5.编写Mapper接口对应的映射文件,命名规范:表名+Mapper.xml 实现sql语句和java程序的分离
6.在mybatis的核心配置文件中通过mappers标签引入接口对应的映射文件
核心配置文件的操作:
1.将数据库连接的相关配置分离出去
2.配置实体类的别名
3.配置mapper映射文件
针对数据库中字段名和类的属性名不一致的情况处理:
1.采用别名的方式解决
2.在mybatis的全局配置文件中进行开启驼峰映射的功能
关于插入后获取生成的标识列的值(—插入字段,返回自动生成的ID—)
<insert id="insertEmp" useGeneratedKeys="true" keyProperty="id">
insert into employees values(null,#{name},#{gender},#{birth},#{deptId})
insert>
一个开放源代码的轻量级J2EE应用程序框架,它提供了企业开发中的一些常见问题的解决方案,为简化开发而生,
Spring 也被称为是容器
,可以整合其他的一些优秀的开源框架
官网地址:https://spring.io
源码下载地址:https://repo.spring.io/ui/repos/tree/General/
IOC【控制反转】和AOP【面向切面编程】
IOC:控制反转
IOC是一种解决特定问题的思想,DI是这种软件设计思想的一个实现,
Spring是实现这个思想的一个具体的框架产品,而Spring中的核心机制就是DI。
解决思路:
1.反射创建对象【动态创建】
2.工厂【负责生产整个项目中的要用到的所有核心对象 service dao mapper.....】将对象的创建和对象的使用两个职责进行分离
3.配置文件
DI:属性注入
实现对象的属性的初始化【给对象属性赋值】
AOP:面向切面编程
通过运行期间
动态代理
实现程序功能的 统一维护
的一种技术
实现目标:实现了方法的主体业务代码和增强的逻辑代码的完全分离【解耦】
首先是开启注解扫描,其次是设置注解扫描的包
1.导入Spring的依赖
2.创建一个spring的配置文件.xml ,一般命名为spring-config.xml applicationContext.xml beans.xml
<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">
beans>
3.在配置文件中配置具体的bean对象
<bean id="student" class="com.qf.entity.Student">bean>
4.编写测试代码从容器中获取对象
@Test
public void test(){
//根据id从spring容器中获取对象\
//创建容器对象
ApplicationContext ctx=new ClassPathXmlApplicationContext("spring-config.xml");
//Object student = ctx.getBean("student");
//按类型获取对象 要求该类型的对象在整个容器中只能是单例
Student s = ctx.getBean(Student.class);
System.out.println(s);
}
第一步:在要注入到IOC容器中的类上面使用@Component注解【相当于是xml中的bean标签的作用】将该类型的对象配置到IOC容器
@Component("userDao")
//相当于
//value="userDao"表示指定当前bean的id为userDao
第二步:开启注解的IOC支持以及配置包扫描
<context:annotation-config/>
<context:component-scan base-package="com.qf"/>
细节说明:
1.如何没有指定bean的id则默认为当前组件类的类名的首字母小写
2.Spring中提供了一些具有语义的注解【@Controller 页面层组件 @Service 业务层 @Repository 持久层】来替代@Component【功能是完全一样的】
属性注入
@Value("${jdbc.driver}")
简单类型
@Autowired
:按类型自动注入【后期使用最多的一个依赖注入注解】
@Qualifier("userDaoImpl1")
按照byName的方式进行自动的依赖注入
@Resource
:该注解是由jdk提供的,被Spring框架支持
第一步:将目标类和切面类都加入到IOC容器中。(@Component注解)
第二步:告诉Spring哪个是切面类。(@Aspect注解)
第三步:在切面类中使用五个通知注解来配置切面。@Before、@AtferReturning、@Around、@AfterThrowing、@After
第四步:开启基于注解的AOP功能。(component-scan、aspectj-autoproxy)
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(* com.qf.oa.service..*.*(..))")
private void pt(){}
//提供增强的方法
@Before("pt()")
public void before(){
System.out.println("前置增强..");
}
@AfterReturning("pt()")
public void afterReturning(){
System.out.println("后置增强..");
}
public void after(){
System.out.println("最终增强..");
}
public void afterThrowing(){
System.out.println("抛出异常增强..");
}
public void round(ProceedingJoinPoint pjp){
// System.out.println("开启事务...");
//调用当前主体业务方法
try {
pjp.proceed();
} catch (Throwable throwable) {
System.out.println("异常处理");
throwable.printStackTrace();
}finally {
//System.out.println("最终处理");
}
// System.out.println("提交事务...");
}
}
<aop:aspectj-autoproxy/>
搭建mybatis的开发环境
导入相关的依赖
编写spring的核心配置文件
Spring 整合Junit方便进行单元测试
在测试类上使用注解创建IOC容器:
在测试类中就可以使用@AutoWired注解进行属性的自动注入
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = {"classpath:spring-config.xml"})
public class AccountServiceTest {
@Autowired
AccountMapper accountMapper;
@Test
public void findAccountList() throws Exception{
List<Account> accounts = accountMapper.selectList();
for (Account account : accounts) {
System.out.println(account);
}
}
}
@RunWith
(测试运行于Spring测试环境)
@ContextConfiguration
和@RunWith
搭配使用
MVC
MVC是一种思想,是Model【模型】 - View【视图】- Controller【控制器】,使用MVC的目的是将M和V的实现代码分离
【解耦】
属于SSM三大框架之一,
专注于web层,简化传统的servlet开发,但是底层依然是基于servlet
SpringMVC框架通过一个前端控制器将客户端发送到服务器的请求全部“引流到”SpringMVC框架的处理流程
创建web项目,设置项目的打包类型为war包,web.xml项目描述文件
导入SpringMVC的依赖
编写控制器类,命名一般以Controller为后缀,并在控制器类中提供请求的处理方法
编写配置文件springmvc.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.qf.mvc.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".jsp"/>
bean>
beans>
编写配置文件web.xml
<servlet>
<servlet-name>DispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>DispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
1.启动tomcat ---->2.加载web.xml核心配置文件---->3.创建前端控制器【DispatcherServlet】—>4.加载springmvc.xml配置文件—>5.创建IOC容器并扫描controller包下的注解---->6.创建控制器对象并加入IOC容器
SpringMVC+Spring+Mybatis
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.7version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.48version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
全局配置文件mybatis-config.xml
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.qf.ssm.entity"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///test"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
dataSource>
environment>
environments>
<mappers>
<package name="com.qf.ssm.mapper"/>
mappers>
configuration>
每张表对应的映射文件
log4j的日志配置log4j.properties
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
log4j.logger.org.apache=INFO
package com.qf.ssm.mapper;
import com.qf.ssm.entity.Account;
import java.util.List;
public interface AccountMapper {
//查询所有账户信息
List<Account> selectList();
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qf.ssm.mapper.AccountMapper">
<select id="selectList" resultType="account">
select * from accounts
select>
mapper>
package com.qf.ssm.test;
import com.qf.ssm.entity.Account;
import com.qf.ssm.mapper.AccountMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class TestMybatis {
@Test
public void testSelectList() throws Exception {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//创建sqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(in);
//创建sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建Mapper代理对象
AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);
List<Account> accounts = mapper.selectList();
for (Account account : accounts) {
System.out.println(account);
}
}
}
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>${spring.version}version>
dependency>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.qf.ssm.service"/>
beans>
导入依赖:spring-test
package com.qf.ssm.test;
import com.qf.ssm.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class TestSpring {
@Autowired
AccountService accountService;
@Test
public void testFindAccountList(){
accountService.findAccountList();
}
}
整合思路:将mybatis框架使用过程中的一些核心对象【SqlSessionFactory Mapper对象】交给IOC容器进行统一的管理
整合的目标:在AccountServiceImpl中能成功的从容器中注入Mapper
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.10version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.6version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>${spring.version}version>
dependency>
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
user=root
password=1234
initialSize=10
maxActive=50
minIdle=5
maxWait=5000
<context:property-placeholder location="classpath:druid.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driverClassName}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
<property name="initialSize" value="${initialSize}"/>
<property name="maxActive" value="${maxActive}"/>
<property name="minIdle" value="${minIdle}"/>
<property name="maxWait" value="${maxWait}"/>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" >
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.qf.ssm.mapper"/>
bean>
package com.qf.ssm.test;
import com.qf.ssm.entity.Account;
import com.qf.ssm.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class TestSpring {
@Autowired
AccountService accountService;
@Test
public void testFindAccountList(){
List<Account> list =
accountService.findAccountList();
for (Account account : list) {
System.out.println(account);
}
}
}
log4j日志框架不符合Slf4j的日志门面
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.25version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>1.7.25version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.13.1version>
dependency>
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.1version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<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:mvc="http://www.springframework.org/schema/mvc"
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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.qf.ssm.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".jsp"/>
bean>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
beans>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>DispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>DispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
package com.qf.ssm.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("account")
public class AccountController {
@RequestMapping("list")
public String getAccountList(){
return "account_list";
}
}
整合的目标:在Controller中可以从容器中注入Service
整合思路:无需借助第三方的整合包,它们是无缝对接,我们希望在tomcat容器启动时能加载到Spring和核心配置文件【applicationContext.xml】,进而创建Spring的IOC容器
具体的实现:在SpringMVC的web模块中提供了一个监听器ContextLoaderListener
public class ContextLoaderListener extends ContextLoader implements ServletContextListener
该监听器实现了ServletContextListener接口,该接口是用来监听ServletContext对象的创建和销毁
ServletContext对象全局只有一份,创建时机发生在tomcat容器启动的时候,并在tomcat容器 销毁时销毁
我们可以将Spring配置文件的加载工作放到监听器的contextInitialized方法中
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
package com.qf.ssm.controller;
import com.qf.ssm.entity.Account;
import com.qf.ssm.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 java.util.List;
@Controller
@RequestMapping("account")
public class AccountController {
@Autowired
AccountService service;
@RequestMapping("list")
public String getAccountList(Model model){
List<Account> accountList = service.findAccountList();
model.addAttribute("list",accountList);
return "account_list";
}
}
所谓的声明式指的是无需编写代码,通过配置的方式进行所有业务方法中事务的统一管理
Spring框架已经提前为我们设计好一个平台事务管理器:PlatformTransactionManager
,这个PlatformTransactionManager只是一个接口,定义了事务管理过程中的一些抽象方法 例如:事务的提交 回滚等操作,针对mybatis框架进行数据访问时使用的是该接口的实现类DataSourceTransactionManager
,从AOP的角度来理解DataSourceTransactionManager就是一个增强【通知】
1.导入事务管理的依赖
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>${spring.version}version>
dependency>
2.在Spring的配置文件中通过bean标签将事务管理器配置到IOC容器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
3.引入tx的名称空间闭关配置事务通知,并在tx:advice标签中配置事务的特性
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
tx:attributes>
tx:advice>
4.进行AOP的配置
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.qf.ssm.service..*.*(..))"/>
aop:config>
@Transactional
@Target({ElementType.TYPE, ElementType.METHOD})
该注解可以注释在类型【class interface】和方法上面
如果注解打在方法上则表示对该方法进行事务控制
如果注解打在类上则表示当前类的所有方法全部进行事务控制
如果打在接口上则表示实现了该接口的所有实现类的所有方法全部进行事务的控制
<tx:annotation-driven/>
注意:SpringMVC的IOC容器和Spring的IOC容器不是一个容器,但是他们之间存在父子关系
子容器中可以注入父容器中的组件,反之不行,在实际的应用中springmvc只负责扫描controller包中的组件,其他所有与表现层无关的组件全部交给spring的IOC容器管理
一个框架的框架,通过简化配置
来进一步简化了Spring应用的整个搭建和开发过程
官网:spring.io
1.依赖管理【场景启动器、起步依赖】2.自动配置
创建独立的Spring应用
Create stand-alone Spring applications
内嵌tomcat 简化项目部署 直接打成一个jar包
Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
提供了一些启动器【场景起步依赖】
Provide opinionated ‘starter’ dependencies to simplify your build configuration
通过自动化配置简化第三方技术的整合
Automatically configure Spring and 3rd party libraries whenever possible
提供了生产环境中的性能 健康监测
Provide production-ready features such as metrics, health checks, and externalized configuration
0 XML
Absolutely no code generation and no requirement for XML configuration
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.3.12.RELEASEversion>
parent>
2…添加一个web开发的起步依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
3…编写一个控制器类
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "hello springboot!";
}
}
4.在当前项目的根包中编写SpringBoot的引导类,里面提供一个main方法来启动spring应用
//表示当前类是一个SpringBoot的引导类
@SpringBootApplication
public class BootApplication {
public static void main(String[] args) {
SpringApplication.run(BootApplication.class,args);
}
}
5.SpringBoot项目部署
直接创建一个可运行的jar包,需要在pom.xml中配置一个springboot的打包插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
1.导入依赖
配置数据源:
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql:///test?characterEncoding=utf8&useSSL=false
username: root
password: 1234
druid:
initial-size: 10
max-active: 50
min-idle: 5
max-wait: 5000
编写Mybatis的配置文件:
#配置mapper接口映射文件的位置
#配置别名的包扫描
#相当于myabtis核心配置文件中的settings
mybatis:
mapper-locations: classpath:mappers/*.xml
type-aliases-package: com.qf.bootmybatis.entity
configuration:
map-underscore-to-camel-case: true
它是一个增强版的Mybatis【不是替代,而是和原来的Mybatis配合使用】,为简化开发而生【提高开发效率】
官网地址:www.baomidou.com`
1.代码自动生成
2.内置分页查询
3.内置全局拦截
…
1.创建Springboot项目
2.导入依赖的坐标
3.编写配置(数据源+端口+实体类+…)
4.编写控制器
SpringSecurity就是基于Spring框架的一个过滤器链
,一共包含了15个过滤器
用于认证【登录】和授权【不同的用户登录同一个系统能够访问的资源是不一样的】
WebAsyncManagerIntegrationFilter:将 Security 上下文与 Spring Web 中用于处理异步请求映射的 WebAsyncManager 进行集成。
SecurityContextPersistenceFilter:
1.在session中初始化SecurityContext,一次会话对应一个上下文
2.SecurityContext上下文可以在用户登录成功后存放用户信息(用户的角色、权限、用户主体信息),所有过滤器共享这个上下文
HeaderWriterFilter:用于将头信息加入响应中。
CsrfFilter:用于处理跨站请求伪造。
LogoutFilter:用于处理退出登录。
UsernamePasswordAuthenticationFilter:拦截/login请求并且是post请求,校验用户名和密码是否正确,如果正确将用户信息存放到Springsecurity的上下文中
DefaultLoginPageGeneratingFilter:拦截/login请求并且是get请求,如果没有指定登录页面,则由该过滤器生成一个默认认证登录页面。
BasicAuthenticationFilter:检测和处理 http basic 认证。
RequestCacheAwareFilter:用来处理请求的缓存。
SecurityContextHolderAwareRequestFilter:主要是包装请求对象request。
AnonymousAuthenticationFilter:检测 SecurityContextHolder 中是否存在 Authentication 对象,如果不存在为其提供一个匿名 Authentication。
SessionManagementFilter:管理 session 的过滤器
ExceptionTranslationFilter:异常转换过滤器位于整个springSecurityFilterChain的后方,用来处理整个链路中出现的异常
FilterSecurityInterceptor:可以看做过滤器链的出口,主要用于判断请求能否通过。**
RememberMeAuthenticationFilter:当用户没有登录而直接访问资源时, 从 cookie 里找出用户的信息, 如果 Spring Security 能够识别出用户提供的remember me cookie, 用户将不必填写用户名和密码, 而是直接登录进入系统,该过滤器默认不开启。
注解
@enablewebsecurity 开启security
@enableglobalmethodsecurity(prePostenabled=true) 开启security的注解功能
usernamepasswordauthenticationfilter
1.当前端提交的是一个 POST 方式的登录表单请求,就会被该过滤器拦截,并进行身份认证。该过滤器的 doFilter() 方法实现在其抽象父类AbstractAuthenticationProcessingFilter中
2.UsernamePasswordAuthenticationFilter 的 attemptAuthentication 方法对前端传过来的用户名和密码进行封装
3.ProviderManager 的 authenticate 方法开始认证
ProviderManager 是 AuthenticationManager 接口的实现类
4.UserDetailsService接口 的 loadUserByUsername方法(一般都由我们自己实现)
从数据库获得用户具体数据
5.AbstractAuthenticationProcessingFilter 的 successfulAuthentication(我们可以重写返回自定义成功)
ExceptionTranslationFilter 过滤器
- 该过滤器是用于处理异常的,不需要我们配置,对于前端提交的请求会直接放行,捕获后续抛出的异常并进行处理(例如:权限访问限制)。
FilterSecurityInterceptor 过滤器
FilterSecurityInterceptor 是过滤器链的最后一个过滤器,该过滤器是过滤器链的最后一个过滤器,根据资源权限配置来判断当前请求是否有权限访问对应的资源。如果访问受限会抛出相关异常,最终所抛出的异常会由前一个过滤器ExceptionTranslationFilter 进行捕获和处理。
SecurityContextPersistenceFilter 过滤器
- 在 UsernamePasswordAuthenticationFilter 过滤器认证成功之后,会在认证成功的处理方法中将已认证的用户信息对象 Authentication 封装进SecurityContext,并存入 SecurityContextHolder。
- 之后,响应会通过 SecurityContextPersistenceFilter 过滤器,该过滤器的位置在所有过滤器的最前面,请求到来先进它,响应返回最后一个通过它,所以在该过滤器中处理已认证的用户信息对象 Authentication 与 Session 绑定。
- 认证成功的响应通过 SecurityContextPersistenceFilter 过滤器时,会从SecurityContextHolder 中取出封装了已认证用户信息对象 Authentication 的SecurityContext,放进 Session 中。当请求再次到来时,请求首先经过该过滤器,该过滤器会判断当前请求的 Session 是否存有 SecurityContext 对象,如果有则将该对象取出再次放入 SecurityContextHolder 中,之后该请求所在的线程获得认证用户信息,后续的资源访问不需要进行身份认证;当响应再次返回时,该过滤器同样从 SecurityContextHolder 取出SecurityContext 对象,放入 Session 中。
@RequestMapping("list") // @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_BZR')") @PreAuthorize("hasAuthority('stu_list')") public String list(){ return "stu_list"; }
登录
授权
单点登录
jsonwebtoken(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的,自包含的方式,用于在各方之间以JSON对象安全地传输信息。
令牌组成:
Header
标头通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法,例如:HMAC SHA256和RSA。
它会使用Base64编码组成JWT结构的第一部分。
注意:Base64是一种编码,也就是说,它是可以被翻译回原来的样子来的。它并不是一种加密过程。
Payload
令牌的第二部分是有效负载,其中包含声明。声明是有关实体(通常是用户)和其他数据的声明。同样的,它会使用Base64编码组成JWT结构的第二部分
Signature
前面两部分都是使用Base64进行编码的,即前端可以解开知道里面的信息。Signature需要使用编码后的header和payload以及我们提供的一个密钥,然后使用header中指定的签名算法(HS256)进行签名。签名的作用是保证JWT没有被篡改过
如:
HMACSHA256(base64UrlEncode(header)+“.”+base64UrlEncode(payload),secret);
授权:
这是使用JWT的最常见方案。一旦用户登录,每个后续请求将包括JWT,从而允许用户访问该令牌允许的路由,服务和资源。单点登录是当今广泛使用JWT的一项功能,因为它的开销很小并且可以在不同的域中轻松使用。
信息交换:
JSON Web Token是在各方之间安全地传输信息的好方法。因为可以对JWT进行签名(例如:使用公钥/私钥对),所以您可以确保发件人是他们所说的人。此外,由于签名是使用标头和有效负载计算的,因此您还可以验证内容是否遭到篡改。
用户携带账号信息登录发给服务端
校验账户是否存在
服务端接收到会采用算法加密封装颁发令牌
令牌分为三部分,head头,payload载荷,第三部分signature签名,head包含令牌类型和算法,jwt和sha265,base64编码
payload包含用户信息(不包含敏感信息)base64编码
1+2然后加上密钥再经过算法加密
三段组合形成jwt令牌
然后发给客户端,客户端拿到jwt令牌,保存在(本地,cookie(少用或者不用))localstoreage
每次发起请求的时候都会把令牌包含在head中发给服务端
服务端验证令牌是否合法,合法在进行权限校验,两个都通过就执行业务流程否则返回错误信息
session的弊端:
- 保存在服务端内存中,占用内存,用户量增大,内存压力增大
- csrf的跨站点攻击,session是基于cookie进行用户识别的,如果cookie被截获,就容易收到跨站点请求伪造攻击。
- 如果搭建多个服务器,虽然业务逻辑都一样,但是内存不是共享的,第一次访问服务器1,第二次访问服务器2,获取不到session信息,就认为没登陆,体验不好
beforeCreate created beforeMount mounted beforeUpdate update beforeDestory destroyed
top 快速查看哪些进程比较消耗CPU和内存资源 free -m 查看操作系统剩余内存空间 df -h 查看磁盘利用率 ps -ef 查看进程 tail -f 查看滚动日志
1:哪个进程的哪个线程特别消耗cpu资源
2:哪个进程哪个对象特别占用内存资源
CPU排查
排查哪个线程最消耗CPU资源
先通过top命令找到最耗CPU的进程id
再通过arthas 监测该进程
通过thread -n 1 查找到最耗CPU的线程
排查内存消耗
分析堆内存为什么占用这么高
通过top找到消耗内存的进程
开启arthas
heapdump --live /export/soft/dump.hprof
jhat dump.hprof
通过ip+端口访问
Nginx(“engine x”)是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的 Web和 反向代理 服务器,能够支持高达 50,000 个并发连接数的响应、占用内存小。
反向代理:
客户端向服务器发送请求时,会首先经过 Nginx 服务器,由服务器将请求分发到相应的 WEB 服务器。正向代理是代理客户端,而反向代理则是代理服务器
负载均衡:
负载均衡*(Load Balance)*其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。
nginx反向代理tomcat 服务集群,将用户的请求均衡到不同服务节点上,从而避免单节点负载过大
静态资源服务器:
Nginx 可以作为前置缓存服务器,它被用于缓存前端请求,从而提高 Web服务器的性能。Nginx 会对用户已经访问过的内容在服务器本地建立副本,这样在一段时间内再次访问该数据,就不需要通过 Nginx 服务器向后端发出请求。减轻网络拥堵,减小数据传输延时,提高用户访问速度。
前端代理
Redis是一个基于内存存储的非关系型(NoSQL)数据库
1:查询缓存
2:分布式锁 setnx
3:秒杀活动数据存储(将Redis当做database来存储商品信息以及用户的下单信息)
4:注册、登录 使用Redis存储验证码(Redis的key可以设置过期时间)
它实际上是一个很长的二进制数组和一系列随机映射(hash)函数。
本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。
优点:
缺点:
存在误判,但是可以通过加到二进制数组的长度以及增加hash的次数来降低误判率
可以用来告诉你 “某样东西一定不存在或者可能存在”。
用来解决redis 缓存穿透的问题:把所有的合法key转成哈希,存入内存中,然后检索查询的key是否存在
基于数据库的全模糊查询存在的弊端:
select * from spu where name like ‘%我喜欢小米手机%’
1:如果使用全模糊查询,会导致索引失效,查询性能很低
2:全模糊查询不能实现商品的站内搜索功能。满足不了业务需求。
分词:ik_smart(最少切分),ik_max_word(最细切分)
elasticsearch官方网址
elasticsearch Github地址ElasticSearch是一个基于Lucene的搜索引擎。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。广泛用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
同类产品 solr
Lucene.jar 语言使用的是java,不能跨语言。
数据 存入到es中,es存在磁盘中
log —> logstash pipeline:管道(数据采集)—> elasticsearch(查询) —> kibana(图表可视化)
beats ,(echart )图表可视化
本质上是倒排索引,
快速搜索,首字母搜索,排行,查询,高亮,品牌与分类聚合,过滤,搜索建议
Easypoi的目标不是替代poi,而是让一个不懂导入导出的快速使用poi完成Excel和word的各种操作,而不是看很多api才可以完成这样工作
@ExcelTarget("user") //设置表头 @Excel(name = "姓名",orderNum = "2") //设置列名 @Excel(name = "编号",orderNum = "1") //orderNum 排序,数值越小越靠前,默认为0 @Excel(name = "性别",orderNum = "3",replace = {"男_0","女_1"}) //replace 替换 0替换男 @Excel(name = "生日",orderNum = "4",width = 100) //width 设置宽度 @Excel(name = "日期",orderNum = "5",format = "yyyy年MM月dd日") //format 日期格式化 @Excel(name = "百分比",orderNum = "4",suffix = "%") //suffix 添加尾缀 @ExcelIgnore //忽略
@ExcelEntity //表示该属性是一个实体类 private Card card; user,setCard(new Card("001","武汉市")) @ExcelCollection(name = "订单信息") //表示该属性是一个集合 private List<Order> orders; user.setOrder(Arrays.asList(new Order("01","小米"),new Order("02","华为")))
1.导入起步依赖
<dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-spring-boot-starter</artifactId> <version>4.0.0</version> </dependency>
允许定义相同的bean对象 去覆盖原有的
spring: main: allow-bean-definition-overriding: true
2.编写实体类 序列化 并 配置注解
User
@Data @NoArgsConstructor @AllArgsConstructor @ExcelTarget("用户列表") public class User implements Serializable { @Excel(name = "编号",orderNum = "1") private Integer id; @Excel(name = "姓名",orderNum = "2") private String name; @Excel(name = "年龄",orderNum = "4",suffix = "岁") private Integer age; @Excel(name="性别",orderNum = "3") private String gender; @Excel(name="生日",orderNum = "5",format = "yyyy年MM月dd日",width = 40) private Date birthday; @ExcelEntity private Details details; @ExcelCollection(name = "订单信息",orderNum = "10") private List<Order> orderList; }
Details
@Data @NoArgsConstructor @AllArgsConstructor @ExcelTarget("用户细节") public class Details implements Serializable { @Excel(name="用户名",orderNum = "6") private String username; @Excel(name="密码",orderNum = "7") private String password; }
Order
@Data @NoArgsConstructor @AllArgsConstructor @ExcelTarget("订单") public class Order implements Serializable { @Excel(name="订单编号",orderNum = "8") private String id; @Excel(name="商品名称",orderNum = "9") private String name; }
3.编写配置类
package com.fy.demo; import cn.afterturn.easypoi.excel.ExcelExportUtil; import cn.afterturn.easypoi.excel.entity.ExportParams; import org.apache.poi.ss.usermodel.Workbook; import java.io.File; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; public class ExportDemo { public static void main(String[] args) throws Exception{ //1.导出设置 ExportParams exportParams = new ExportParams(); exportParams.setTitle("用户列表"); //设置表格头 exportParams.setSheetName("用户列表sheet"); //设置表名 //2.数据准备 List<User> users = new ArrayList<User>(){{ add(new User(1,"张三",89,"男",new Date(),new Details("三三","123"),Arrays.asList(new Order("0100","小米"),new Order("0120","小米10")))); add(new User(2,"李四",78,"男",new Date(),new Details("ss","123"),Arrays.asList(new Order("0200","华为"),new Order("0220","华为60")))); add(new User(3,"王五",67,"男",new Date(),new Details("ww","123"),Arrays.asList(new Order("0300","vivo"),new Order("0330","vivox21")))); }}; Workbook workbook = ExcelExportUtil.exportExcel(exportParams, User.class, users); //3.文件输出 FileOutputStream fileOutputStream = new FileOutputStream( new File("C:\\Users\\方子琰\\OneDrive\\桌面\\sprint-vue-kaoshixitong\\user.xls") ); workbook.write(fileOutputStream); fileOutputStream.close(); workbook.close(); } }
1.编写映射 的实体类
...
2.编写配置类
package com.fy.demo; import cn.afterturn.easypoi.excel.ExcelImportUtil; import cn.afterturn.easypoi.excel.entity.ImportParams; import java.io.File; import java.io.FileInputStream; import java.util.List; public class ImportDemo { public static void main(String[] args) throws Exception{ //1.文件输入流 FileInputStream fileInputStream = new FileInputStream( new File("C:\\Users\\方子琰\\OneDrive\\桌面\\sprint-vue-kaoshixitong\\user.xls") ); ImportParams importParams = new ImportParams(); importParams.setTitleRows(1); //指定标题占用行数 importParams.setHeadRows(2); //指定表头占用行数 importParams.setSheetNum(1); List<User> userList = ExcelImportUtil.importExcel(fileInputStream, User.class, importParams); userList.forEach(System.out::println); } }
//导出
@GetMapping("export")
public void export(HttpServletResponse response)throws Exception{
//获取数据
List<SysUser> users = userMapper.findAll();
//导出
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("用户信息", "user_list")
, SysUser.class, users);
//设置响应
response.setHeader("content-disposition","attachment;fileName="+ URLEncoder.encode("用户列表.xls","UTF-8"));
response.setContentType("application/vnd.ms-excel;charset=utf-8");
ServletOutputStream outputStream = response.getOutputStream();
workbook.write(outputStream);
outputStream.close();
workbook.close();
}
1:微服务是一种项目架构思想(风格)
2:微服务架构是一系列小服务的组合(组件化与多服务)
3:任何一个微服务,都是一个独立的进程(独立开发、独立维护、独立部署)
4:轻量级通信http、RPC协议(跨语言,跨平台)
5:服务粒度(围绕业务模块拆分)
6:去中心化管理(去中心化”地治理技术、去中心化地管理数据、编程语言)
1.易于开发和维护
一个微服务只关注一个特定的业务功能,所以它的业务清晰、代码量较少。开发和维护单个微服务相对比较简单,整个应用是由若干个微服务构建而成,所以整个应用也会维持在可控状态;
2.单个微服务启动较快
单个微服务代码量较少,所以启动会比较快;
3.局部修改容易部署
单体应用只要有修改,就要重新部署整个应用,微服务解决了这样的问题。一般来说,对某个微服务进行修改,只需要重新部署这个服务即可;
4.技术栈不受限
在微服务中,我们可以结合项目业务及团队的特点,合理地选择技术栈
1、服务太多,导致服务间的依赖错综复杂,运维难度大
2、微服务放大了分布式架构的系列问题
3、运维复杂度陡增,部署数量多、监控进程多导致整体运维复杂度提升。
4、互联网系统(用户群体大、访问量大、并发量大)
添加以下两个html文件
resources/templates/error/4xx.html
resources/templates/error/5xx.html
1.编写一个自定义异常类(exception/CustomException)
package com.fzy.day65.exception;
public class CustomException extends RuntimeException{
public CustomException(String message){
super(message);
}
}
2.编写一个全局异常处理类(exception/GlobalExceptionHandler)
package com.fzy.day65.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
//定义一个全局异常处理类
@ControllerAdvice
public class GlobalExceptionHandler {
//处理自定义类型的异常
@ExceptionHandler(CustomException.class)
@ResponseBody
public String handleCustomException(Exception ex){
// 保存异常的信息
// 给客户端一个友好的提示
return ex.getMessage();
}
//处理非自定义异常
@ExceptionHandler(Exception.class)
@ResponseBody
public String handleException(Exception ex){
// 保存异常的信息
// 给客户端一个友好的提示
return "未知错误!";
}
}
3.编写控制器类
package com.fzy.day65.controller;
import com.fzy.day65.exception.CustomException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@RequestMapping("/test")
public String test(){
// int i=1/0;
if(true){
throw new CustomException("数据类型异常!");
}
return "这是一个测试";
}
}