SSM框架学习

软件架构:

基于流行SSM框架:Spring+SpringMVC+Mybatis

项目配置: 使用Maven进行项目jar导入

​ 使用Git进行版本控制,并将每次编写的代码上传到Gitee进行保存

环境需求:

​ IDEA(装有Web相关插件以及Maven插件和Git插件)

​ Navcat(mysql 5.7 图形化管理工具)

​ JDK 1.8

环境配置

​ IDEA中的Maven配置,Git配置,请自行查阅,网上有相关资源

参考网站:

Maven Repository : https://mvnrepository.com/

Gitee:https://gitee.com/

Gitee 项目仓库:https://gitee.com/xuzhi7162/SSM

GitHub项目仓库:https://github.com/xuzhi7162/SSM/tree/master/NewProject/JavaWebTest

(使用IntelliJ IDEA尝试开发)

Mybatis教程:https://blog.csdn.net/hellozpc/article/details/80878563#3Mybaits_109

SpringMVC文档地址(老版):https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#overview-distribution-zip

Mybatis

日志工具

##引入相关依赖

<!-- log4j日志依赖 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency>

##在全局配置文件中添加相应的setting设置

<settings><!-- 添加日志相关setting配置,目的是在控制台能够看出打印日志,可以看到执行的SQL语句 --><setting name="logImpl" value="LOG4J"/>
</settings>

##在resources目录下建立log4j.properties配置文件,并在内部做出相应修改

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.com.xuzhi.mapper=DEBUG
# 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.mybatis.example.BlogMapper.selectBlog=TRACE

修改为

log4j.logger.com.xuzhi.mapper=DEBUG

即将原先的org.mybatis.example.BlogMapper.selectBlog修改为你mapper所在的包,并将后面的TRACE修改为DEBUG以便于在控制台打印

mybatis-config.xml

##Mybatis的全局配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><properties><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis"/><property name="username" value="root"/><property name="password" value="xuzhi7162"/></properties><settings><!-- 添加日志相关setting配置,目的是在控制台能够看出打印日志,可以看到执行的SQL语句 --><setting name="logImpl" value="LOG4J"/></settings><environments default="mybatis"><!-- 可以配置多个environment环境,但是每个环境都必须拥有其唯一的id识别,不可重复,default用来选择某一个具体的environment环境,变量值为id的值 --><environment id="mybatis"><transactionManager type="JDBC" /><dataSource type="UNPOOLED"><property name="driver" value="${driver}" /><property name="url" value="${url}" /><property name="username" value="${username}" /><property name="password" value="${password}" /></dataSource></environment></environments><!-- 添加Mybatis的配置文件,具体实体类对应具体配置文件,注意:添加路径时必须使用"/",不能使用"." --><mappers><!-- 还有其他方法,常用的就以下两种,多推荐第二种,否则当有很多个mapper接口时配置文件会变得较为冗长 --><!-- 方法一:直接引入某个mapper接口的具体配置文件 --><mapper resource="com/xuzhi/mapper/UserInfoMapper.xml" /><!-- 方法二:直接引入mapper接口所在的包,以后只要在该包下的mapper接口都可直接使用,不需要再               重新引入  --><package name="com/xuzhi/po"/></mappers>
</configuration>

##两种mapper引入方法:直接引入配置文件,引入实体类所在的包

UserInfoMapper.xml

##UserInfoMapper实体类的配置文件,该配置文件必须在全局配置文件mybatis.cfg,xml中注册

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace必须指定到相应的mapper接口,可以用"."连接 -->
<mapper namespace="com.xuzhi.mapper.UserInfoMapper"><!-- 插入操作 --><insert id="insert" parameterType="com.xuzhi.po.UserInfo">insert into user_info(user_name,user_pass,user_phone) values(#{userName},#        {userPass},#{userPhone})</insert>
</mapper>

##对相应数据表的GRUD操作的语句都写于该配置文件中,

#{}和${}

#{} 只是替换?,相当于PreparedStatement使用占位符去替换参数,可以防止sql注入。
是进行字符串拼接,相当于sql语句中的Statement,使用字符串去拼接sql;{} 是进行字符串拼接,相当于sql语句中的Statement,使用字符串去拼接sql;是进行字符串拼接,相当于sql语句中的Statement,使用字符串去拼接sql;可以是sql中的任一部分传入到Statement中,不能防止sql注入。

注:所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

MybatisUtil.java工具类

##用与返回SqlSession

package com.xuzhi.util;import java.io.IOException;
import java.io.InputStream;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;/***  单例类,在程序中仅有一个类* @author 绪志**/
public class MybatisUtil {private static SqlSessionFactory sqlSessionFactory;/***   静态代码块,在程序的所有运行过程中,该代码块仅执行一次,类似于单例*/static {//指定全局配置文件String resource="mybatis.cfg.xml";InputStream in=null;try {//读取配置文件in = Resources.getResourceAsStream(resource);//构建SqlSessionFactorysqlSessionFactory = new SqlSessionFactoryBuilder().build(in);} catch (IOException e) {e.printStackTrace();}finally {if(in != null){try {in.close();} catch (IOException e) {e.printStackTrace();}}}}public static SqlSession getSession(){//返回SqlSessionreturn sqlSessionFactory.openSession();}
}

UserInfoMapper.java

package com.xuzhi.mapper;import com.xuzhi.po.UserInfo;
/*** 该接口中主要是对UserInfo实体类的GRUD操作,不需要实现该接口,仅需要在UserInfoMapper.xml中添加相应的sql语句既可* @author 绪志**/
public interface UserInfoMapper {int insert(UserInfo userInfo);
}

SQL语句

select复合查询语句

##推荐使用注解方法 @Param()

/*** 通过name和flower进行复合查询,通过注解可以在mapper的配置文件中直接使用#{name}和#{flower}来接收参数* 否则必须使用mybatis默认的参数接收方式,param1,param2或者arg0,arg1* 推荐使用注解的方式来进行传递参数* @param name* @param flower* @return*/Girl queryByNameFlower(@Param("name") String name,@Param("flower") String flower);

##通过就Javabean进行参数传递

/*** 通过javabean来传递参数* mapper.xml中调用参数时只需要使用实体类中的属性名即可* @param girl* @return*/Girl queryByNameFlower1(Girl girl);

###在传入多个javabean时,在接收参数时可以使用param1.XXX,此方法是不友好的,可以在定义方法时使用@Param注解,

例:@Param(“a”) Girl girl==========使用时可以使用"a.XXX"

##通过hashmap进行参数传递(在mapper中按照键的名称取值)

/*** 通过hashmap传参* @return*/Girl queryByNameFlower2(Map<String,Object> map);

动态SQL

##本部分没有做测试类,完全摘自Mybatis官方文档

  • if

  • choose (when, otherwise)

  • trim (where, set)

  • foreach

  • bind

  • sql

if

动态 SQL 通常要做的事情是根据条件包含 where 子句的一部分。比如:

<select id="findActiveBlogLike" resultType="Blog">SELECT * FROM BLOG <where> <if test="state != null">AND state = #{state}</if> <if test="title != null">AND title like #{title}</if><if test="author != null and author.name != null">AND author_name like #{author.name}</if></where>
</select>

##在使用where条件是可以使用专门的标签,从而使mybatis自动处理查询条件前面的‘and’关键字,推荐在所有的if语句中所有的查询关键字前面都加上and关键字,即使是第一个在其内容中也要加入and关键字,因为mybatis会帮我们处理好这个and关键字,例如

<where> <if test="state != null">AND state = #{state}</if>
</where>
choose, when, otherwise

##有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

<select id="findActiveBlogLike"resultType="Blog">SELECT * FROM BLOG WHERE state = ‘ACTIVE’<choose><when test="title != null">AND title like #{title}</when><when test="author != null and author.name != null">AND author_name like #{author.name}</when><otherwise>AND featured = 1</otherwise></choose>
</select>
trim, where, set

标签代码同标签内的代码

标签可以看成为的自定义标签,可以通过内部的某些属性来处理AND/OR,还可以处理“,”

<trim prefix="WHERE" prefixOverrides="AND |OR ">...
</trim>

###官方文档没有完全给出标签内的所有属性,具体使用时需要具体百度

标签可以处理标签中多余的“,”,例如update中的set后项目的“,”

<update id="updateAuthorIfNecessary">update Author<set><if test="username != null">username=#{username},</if><if test="password != null">password=#{password},</if><if test="email != null">email=#{email},</if><if test="bio != null">bio=#{bio},</if></set>where id=#{id}
</update>

###同标签处理AND/OR一样,可以在每个语句的后面都填上“,”,标签都可以帮我们处理掉

foreach
<select id="selectPostIn" resultType="domain.blog.Post">SELECT *FROM POST PWHERE ID in<foreach item="item" index="index" collection="list" open="(" separator=","                  close=")">#{item}</foreach>
</select>

​ · item:自命名,用来表示需要遍历的集合的其中的一个子项

​ ·index:当前遍历到的下标

​ ·collection:需要遍历的类型 #list、set、map

​ ·open:以什么为开始

​ ·separator:每个子项之间用什么符号分隔开

​ ·close:以什么为结尾

上述代码可“编译出”,

select * from post p where ID in (a,b,c,d)
bind

###bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:

<select id="selectBlogsLike" resultType="Blog"><bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />SELECT * FROM BLOGWHERE title LIKE #{pattern}
</select>
sql

这个元素可以被用来定义可重用的 SQL 代码段,可以包含在其他语句中。它可以被静态地(在加载参数) 参数化. 不同的属性值通过包含的实例变化. 比如:

<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>

这个 SQL 片段可以被包含在其他语句中,例如:

<select id="selectUsers" resultType="map">select<include refid="userColumns"><property name="alias" value="t1"/></include>,<include refid="userColumns"><property name="alias" value="t2"/></include>from some_table t1cross join some_table t2
</select>

Mybatis关系映射

##使用mybatis处理一般的单表时常使用resultType属性,但是用mybatis处理多表查询时,使用resultType进行结果集的封装不太适用,所以此时要使用自定义封装结果集,多使用resultMap进行自定义结果集的封装

一对一关系映射

##简要说明,一对一举例,一个用户拥有自己独特的个人信息,一个用户对应一个用户详情信息

<方法一:使用assocation进行具体对象的封装>

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xuzhi.mapper.GirlDetailMapper"><!--对应一般的单表查询,我们用mybatis的resultType就可以解决但是对于多表联合查询我们就需要使用resultMap来进行详细描述返回值处理--><!--可以变编写一个父resultMap,子resultMap可以继承父resultMap,以减少重复代码量在子resultMap中增加extends=“父id”就可以使用父resultMap--><resultMap id="BaseGirlDetail" type="com.xuzhi.model.GirlDetail"><id property="id" column="uid" /><result property="name" column="name" /><result property="flower" column="flower" /><result property="birthday" column="birthday" /></resultMap><!--封装方式一:使用assocation--><resultMap id="GirlWithDetailMap" type="com.xuzhi.model.GirlDetail"><id property="id" column="uid" /><result property="name" column="name" /><result property="flower" column="flower" /><result property="birthday" column="birthday" /><association property="girlWithDetail" javaType="com.xuzhi.model.GirlWithDetail"><id property="gid" column="gdid" /><result property="address" column="address" /></association></resultMap><!--封装方式二:使用;连缀方式--><resultMap id="GirlWithDetailMap2" type="com.xuzhi.model.GirlDetail"><id property="id" column="uid" /><result property="name" column="name" /><result property="flower" column="flower" /><result property="birthday" column="birthday" /><!--连缀写法  "XXX.xx"--><result property="girlWithDetail.gid" column="gdid" /><result property="girlWithDetail.address" column="address" /></resultMap><!--封装方式三支持分步查询,如果有的查询过于复杂,可以使用分步查询的方法进行查询extends属性表示使用父resultMap--><resultMap id="GirlWithDetailMap3" extends="BaseGirlDetail" type="com.xuzhi.model.GirlDetail"><!--对于复杂的javabean属性,则由我们自己处理(及返回结果集中的某一个属性是具体的javabean)完场第一次查询后会调用assocation中select调用的查询,讲将结果封装到相应的javabean并赋值给property,完成查询column属性表示一级查询到的某一列的值作为参数传给二级查询条件--><association property="girlWithDetail" select="com.xuzhi.mapper.GirlWithDetailMapper.queryById" column="uid"></association></resultMap><select id="queryById" resultMap="GirlWithDetailMap2">select t1.id as uid,t1.`name`,t1.flower,t1.birthday,t2.id as gdid, t2.addressfrom girl t1,girl_detail t2<where>t1.id=t2.gidand t1.id=#{id}</where></select><!--多表联合查询--><select id="queryByIdByStep" resultMap="GirlWithDetailMap3">select t1.id as uid,t1.`name`,t1.flower,t1.birthdayfrom girl t1<where>and t1.id=#{id}</where></select>
</mapper>

##对于javabean的封装多使用oop思想

Girl.java

package com.xuzhi.model;import java.io.Serializable;
import java.util.Date;public class Girl implements Serializable {private long id;private String name;private String flower;private Date birthday;public long getId() {return id;}public void setId(long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getFlower() {return flower;}public void setFlower(String flower) {this.flower = flower;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public Girl(String name, String flower){this.name=name;this.flower=flower;}public Girl(){}@Overridepublic String toString() {return "Girl{" +"id=" + id +", name='" + name + '\'' +", flower='" + flower + '\'' +", birthday=" + birthday +'}';}
}

GirlWithDetail.java

package com.xuzhi.model;import java.io.Serializable;public class GirlWithDetail implements Serializable {private Integer gid;private String address;private Girl girl;public Integer getGid() {return gid;}public void setGid(Integer gid) {this.gid = gid;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Girl getGirl() {return girl;}public void setGirl(Girl girl) {this.girl = girl;}@Overridepublic String toString() {return "GirlWithDetail{" +"gid=" + gid +", address='" + address + '\'' +'}';}
}

GirlDetail.java

package com.xuzhi.model;import java.io.Serializable;public class GirlDetail extends Girl{private GirlWithDetail girlWithDetail;public GirlWithDetail getGirlWithDetail() {return girlWithDetail;}public void setGirlWithDetail(GirlWithDetail girlWithDetail) {this.girlWithDetail = girlWithDetail;}@Overridepublic String toString() {return "Girl{" +"id=" + getId() +", name='" + getName() + '\'' +", flower='" + getFlower() + '\'' +", birthday=" + getBirthday() +'}'+"GirlDetail{" +"girlWithDetail=" + girlWithDetail +'}';}
}
一对多关系映射

##一对多关系映射举例:一个用户可以写多篇博客

##废话不多说,几段代码可以说明一切

GirlWithBlogMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xuzhi.mapper.GirlWithBlogMapper"><resultMap id="BaseGirlDetail" type="com.xuzhi.model.GirlDetail"><id property="id" column="gid" /><result property="name" column="name" /><result property="flower" column="flower" /><result property="birthday" column="birthday" /></resultMap><resultMap id="girlWithBlogMap" extends="BaseGirlDetail" type="com.xuzhi.model.GirlBlog" ><!--ofType是用来描述集合中元素的数据类型--><collection property="blog" ofType="com.xuzhi.model.Blog"><id property="id" column="bid" /><result property="title" column="title" /><result property="summary" column="summary" /><result property="content" column="blogContent" /><collection property="comments" ofType="com.xuzhi.model.Comment"><id  property="id" column="cid"/><result property="content" column="commentContent" /></collection></collection></resultMap><select id="queryByIdWithBlog" resultMap="girlWithBlogMap">SELECT t1.id as gid,t1.`name`,t1.flower,t1.birthday,t2.id as bid,t2.title,t2.summary,t2.content as blogContent,t3.id as cid,t3.content as commentContentfrom girl t1,blog t2,`comment` t3<where>t1.id=t2.g_idand t2.id=t3.b_idand t1.id=#{id}</where></select>
</mapper>

Blog.java

package com.xuzhi.model;import java.util.List;public class Blog {private Integer id;private String title;private String summary;private String content;private Girl girl;private List<Comment> comments;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getSummary() {return summary;}public void setSummary(String summary) {this.summary = summary;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public Girl getGirl() {return girl;}public void setGirl(Girl girl) {this.girl = girl;}public List<Comment> getComments() {return comments;}public void setComments(List<Comment> comments) {this.comments = comments;}@Overridepublic String toString() {return "Blog{" +"id=" + id +", title='" + title + '\'' +", summary='" + summary + '\'' +", content='" + content + '\'' +", girl=" + girl +", comments=" + comments +'}';}
}

Comment.java

package com.xuzhi.model;public class Comment {private Integer id;private String content;private Blog blog;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public Blog getBlog() {return blog;}public void setBlog(Blog blog) {this.blog = blog;}@Overridepublic String toString() {return "Comment{" +"id=" + id +", content='" + content + '\'' +'}';}
}

GirlBlog.java

package com.xuzhi.model;import java.util.List;public class GirlBlog extends Girl {private List<Blog> blog;public List<Blog> getBlog() {return blog;}public void setBlog(List<Blog> blog) {this.blog = blog;}@Overridepublic String toString() {return  "Girl{" +"id=" + getId() +", name='" + getName() + '\'' +", flower='" + getFlower() + '\'' +", birthday=" + getBirthday() +'}'+"GirlBlog{" +"blog=" + blog +'}';}
}

###简要说明:

​ 在该例中,一个Girl用户可以拥有多个Blog,一个Blog又可以拥有多个Comment,这就构成了简单的一对多关系,其中还是使用了oop思想,最终想要封装的结果集类型是GirlBlog类型,在该类型包含了用户的部分个人信息,还包括了该用户的Blog,在每个Blog中有包含了该Blog所拥有的Comment,在Blog和GirlBlog中分别使用了List和List来反应一对多关系

Spring

基础技术

  • java
  • 反射
  • xml
  • xml解析
  • 代理
  • 大量设计模式

环境搭建

​ 1、添加spring依赖

​ 2、编写一个spring的配置文件

​ 3、通过spring的应用程序上下文对象获取对象

环境配置测试

spring全局配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="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 "><!--将对象的创建交给spring容器,在这个配置文件里面去声明我需要什么文件class:写java类的全限定类名,他是通过全类名然后使用反射的技术进行创建的id:ID就是给这个对象在整个应用程序上下文当中去个名以方便区分--><bean class="com.xuzhi.pojo.Girl" id="girl"></bean></beans>

bean类

###Girl.java

package com.xuzhi.pojo;public class Girl {private String name;private Integer age;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Girl{" +"name='" + name + '\'' +", age=" + age +'}';}
}

###测试类–>SpringTest.java

package com.xuzhi.spring;import com.xuzhi.pojo.Girl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class SpringTest {@Testpublic void test1(){// 1、获取上下文对象,spring里面声明对象都需要通过上下文来获取//在引入配置文件的时候,可以同时引入多个配置文件,在ClassPathXmlApplicationContext中使用String数组作为参数/* 例:ApplicationContext ctx=new ClassPathXmlApplicationContext(new String[]{"xxx1.xml","xxx2.xml"});*/ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");// 2、通过这个对象来获取girlGirl girl= (Girl) ctx.getBean("girl");//因为后面指定了class,所以不需要进行强制类型转换(个人感觉这种方式比较好)//Girl girl =ctx.getBean("girl",Girl.class);System.out.println(girl);}
}
普通代码编写与spring方式编写的

​ 普通的获取对象的方式,所有的对象之间的依赖,类之间的依赖关系都是在java代码里面维护的,很难维护的,如果说我们有替换方案,替换比较困难

​ 对象的产生全部是在配置里面完成的,其实我们想分析关系,直接在配置文件里面就看出来了。

核心内容学习
  • IOC
  • AOP​

IOC概念(依赖注入):

​ 控制反转(inverse of contril ):什么控制,谁反转了谁

​ 控制:创建对象,彼此关系的权利

​ 普通方式:控制权是在开发人员在程序代码当中进行掌控,new

​ spring方式:夺取控制权,反转给spring的容器

反转过程:

​ 声明要什么

​ spring容器来进行具体的控制

​ 依赖注入:

​ 依赖:

​ 容器

​ pojos:自己定义的这些类

​ metadata:在spring的配置文件里面写的这些就是元数据

​ 实例化容器:classpath…将配置文件传入,实例化完毕

值的注入

​ setter()方法注入(最常用的方法)

​ 必须其字段有对应的setter()方法才可完成

​ 通过property子节点完成注入

​ 构造注入

bean元素探讨

​ 属性探讨

abstract:该bean将无法被实例化

parent:指定它的父bean是谁,将会继承父bean的所有内容,通过id进行指引

destroy-method:指定这个bean最后销毁的时候一定执行的方法,适合于清理型工作,触发条件是必须bean确实是被销毁才生效

​ 容器close被触发

​ refresh也会触发

​ 过时的destroy也可以触发

init-method:指定bean的初始化方法,准备性的工作

name:别名,可以通过他一样获取,可以写多个,彼此分割可以使用多种分隔符,空格,逗号等等,

<bean class="com.xuzhi.pojo.Girl" id="girl" abstract="true" destroy-method="clearDress" init-method="dress" name="g1,g2,g3"><!--name指定要注入的属性名称,value给其赋值--><property name="name" value="myFirends" /></bean>

注:clearDress是Girl类里面的一个方法名,dress也是如此,

scope:指定范围

​ singleton:单例,在spring上下文当中,只有一个实例

​ prototype:原型,要一个就给一个

lazy-init:true就是spring一上来不会直接初始化我们的bean,当我们需要使用它的时候,spring才会初始化

​ 直接初始化

​ 当应用程序启动会慢一点,内存消耗会更大一点

​ 当我们使用bean的时候会快一些

​ 延迟初始化

​ 程序启动快一些,内存消耗更小一点

​ 使用bean会慢一点

depends-on:依赖的bean,如果某一个bean的使用严重依赖于另外一个bean的准备的话,就可以配置depends-on

对于非字面值可以描述的值的注入问题

 <bean id="pay" class="com.xuzhi.spring.AliPay"></bean><bean id="girl" class="com.xuzhi.pojo.Girl" ><!--非字面值可描述的属性注入,必须通过ref来描述--><property name="pay" ref="pay" /></bean>

通过ref指向另外一个bean的ID

关于在spring的配置文件当中单独定义别名

​ alias标签完成

spring多个配置文件里面的bean是可以相互引用的(被上下文扫描到的前提下)

构造注入:

构造注入方式一:

<!--构造注入方式一:通过名字来注入--><bean id="car" class="com.xuzhi.pojo.Car"><constructor-arg name="name" value="宝马" /><constructor-arg name="price" value="12123123123" /><constructor-arg name="speed" value="123123" /></bean>

构造注入方式二:(不推荐使用,实在是太垃圾了了)

<!--构造注入方式二:--><bean id="car2" class="com.xuzhi.pojo.Car"><constructor-arg index="0" value="宝马" /><constructor-arg index="1" value="123123" /></bean>
public Car(String name, double price) {this.name = name;this.price = price;}public Car(double price, double speed) {this.price = price;this.speed = speed;}public Car(String name, double price, double speed) {this.name = name;this.price = price;this.speed = speed;}

注:他优先时候后面的构造器

构造注入方式三:(不推荐使用,感觉还是很垃圾的)

###根据构造方法里面的参数的类型注入

<!--构造方法注入三:--><bean id="car3" class="com.xuzhi.pojo.Car" ><constructor-arg type="java.lang.String" value="宝马" /><constructor-arg type="java.lang.Double" value="123" /></bean>

Spring中各种值的注入

数组、List、Set、Map

如果其对应的值是简单的字面值,就直接写就可以了,如果是一个其他的类,那么使用内部bean的方式完成

<bean class="com.xuzhi.pojo.People" id="people" ><property name="name" value="小明" /><property name="age" value="12" /><property name="friends"><array><value>小红</value><value>小刚</value><value>你爸爸</value></array></property><property name="numbers"><list><value>1</value><value>2</value><value>3</value></list></property><property name="girls"><list><!--内部bean,不能被外部所引用--><bean class="com.xuzhi.pojo.Girl"><property name="name" value="nihao" /></bean><bean class="com.xuzhi.pojo.Girl"><property name="name" value="测试" /></bean></list></property><property name="pays"><set><bean class="com.xuzhi.spring.AliPay"></bean><bean class="com.xuzhi.spring.AliPay"></bean></set></property><property name="girlMap"><!--entry标签时map的键名,里面的内容是值--><map><entry key="girl1"><bean class="com.xuzhi.pojo.Girl"><property name="name" value="nihaoi" /></bean></entry><entry key="girl2"><bean class="com.xuzhi.pojo.Girl"><property name="name" value="nihaoi" /></bean></entry></map></property></bean>

自动注入

###最新的官方文档推荐是用自动注入

  • byType:按照数据类型注入
  • byName:按照bean对应的pojo里面的属性的名字来进行匹配
  • constructor
    • 有限按照类型去匹配,如果匹配到一个那么直接注入,不止一个按照名字注入,如果一个都找不到,注入失败
  • default
  • none
<!--byType注入--><!--<bean class="com.xuzhi.pojo.Girl" id="girl" autowire="byType">--><!--<property name="name" value="Girl1" />--><!--<property name="age" value="12" />--><!--</bean>--><!--primary默认值为true如果有多个bean,并且它会按类型注入给其他bean,那么只能有一个primary为true--><!--<bean  class="com.xuzhi.spring.AliPay" primary="true" >--><!--</bean>--><!--<bean class="com.xuzhi.spring.WXPay" primary="false" >--><!--</bean>--><!--byName注入--><!--<bean class="com.xuzhi.pojo.Girl" id="girl" autowire="byName">--><!--</bean>--><!--<bean class="com.xuzhi.spring.AliPay" name="pay">--><!--</bean>--><!--constructor注入--><!--<bean class="com.xuzhi.pojo.Girl" id="girl" autowire="constructor">--><!--<constructor-arg name="name" value="nihao" />--><!--</bean>--><!--<bean class="com.xuzhi.spring.AliPay" name="pay">--><!--</bean>-->

配置文件处理

<!--该配置文件为spring的整体配置文件,所有的spring操作只需要引用这一个配置文件即可因为在该配置文件中引用了其他的配置文件其他的每一个配置文件都分别对应了各自的要求例如:spring-mybatis.xml=>说明spring和mybatis整合是所需要的配置文件--><!--这个标签可以将其他的配置文件引入,这样的话,我们将来整体读取这一个文件即可--><!--分别导入配置文件--><import resource="classpath:spring/spring-test.xml" /><import resource="classpath:spring/spring-test2.xml" /><!--可以导入spring文件夹下所有以spring-开头的配置文件--><import resource="classpath:spring/spring-*.xml" />
<!--通过这种方式引入我们类路径下的文件--><context:property-placeholder location="classpath:jdbc.properties" /><bean class="com.xuzhi.pojo.DaoTest" id="jdbc" ><!--${}表达式可以可以去引用我们引入的这些properties里面的属性的值,通过他的键名得到值--><property name="url" value="${url}" /><property name="driver" value="${driver}" /><property name="username" value="${username}" /><property name="password" value="${password}" /></bean>

注:使用import等标签时需要完整的xml命名空间

Spring常用注释

  • Component
  • Controller =>(SpringMVC)
  • Service=>(业务层)
  • Respository=>(dao层)

spring AOP

额外补充依赖
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.2</version>
</dependency>
配置文件
<!--1、AOP是基于代理完成的,所以要激活我们的自动代理-->
<aop:aspectj-autoproxy />
<!--2、注册一个切面要使用的类-->
<bean class="com.xuzhi.advice.BeforeAdvice" id="beforeAdvice" >
</bean>
<!--3、配置切入点等信息-->
<aop:config><aop:aspect id="beforeAspect" ref="beforeAdvice"><!--aop:before 表明他确实是前置通知method:指明他是使用哪个具体的方法来切pointcut:切入点要切什么包下面的什么类下面的什么方法--><!--如果有多个相同类型的建议,谁再前谁先执行--><aop:before method="methodBefore" pointcut="execution(* com.xuzhi.service.ProviderService.add(..))" /><aop:before method="before" pointcut="execution(* com.xuzhi.service.ProviderService.add(..))" /></aop:aspect><aop:aspect id="afterAspect" ref="afterAdvice"><!--execution(* com.xuzhi.service.ProviderService.add(..)) 切带有任意参数或者不带参数的add()方法execution(* com.xuzhi.service.ProviderService.add()) 切无参数的方法execution(* com.xuzhi.service.ProviderService.add(String))  切只有一个String类型参数的方法execution(* com.xuzhi.service.ProviderService.add(String,int)) 切同时含有String和int类型的方法--><aop:after method="methodAfter" pointcut="execution(* com.xuzhi.service.ProviderService.add(String,int))" /></aop:aspect>
</aop:config>
//JoinPoint可以获取几乎所有的这个方法的信息
//作用,可以打印输出日志文件
public void before(JoinPoint joinPoint){//获取方法的方法名String name=joinPoint.getSignature().getName();System.out.println("method:"+name);//获取方法的参数Object[] args = joinPoint.getArgs();System.out.println(Arrays.toString(args));
}

AOP注解版

  • Configuration:表明一个类为配置类,程序启动的时候只要扫描这个类,就可以清楚所有的配置规则
  • Component:表明一个类为spring的一个组件,可以被spring容器所管理,他是一个普通组件的语义
  • Service:同上,语义上属于服务层
  • Repository:同上,语义上属于DAO层
  • Controller:同上,语义上属于控制层
  • ComponentScan:组件扫描,可以决定去扫描那些包
  • Bean:用于在spring容器当中注册一个bean
  • Autowired:自动注入组件

execution表达式

先写访问修饰符,包名的限定,类名,方法名,参数列表+组合条件符合,多个条件很都可以

<!--访问修饰符为public的并且是sz这个包或者包下面的任意的类的任意的方法的参数为一个,并且类型为String的方法,就可以切到
-->
public com.sz..*.*(String)public com.sz.*.*.*(Integer )

SpringMVC

使用步骤:

1、创建web项目

2、编写web.xml,在其中注册一个特殊的servlet,前端控制器

3、编写一个springmvc的配置文件

​ 1、注册一个视图解析器

4、编写控制器

5、编写一个结果页面

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://xmlns.jcp.org/xml/ns/javaee"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"><!--注册一个前端控制器--><servlet><!--如果我们不去修改spring配置文件默认的位置,那么springmvc会去web-inf路径下的springmvc-servlet.xml文件--><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class></servlet><!--servlet映射配置--><servlet-mapping><servlet-name>springmvc</servlet-name><!--统一写“/”--><url-pattern>/</url-pattern></servlet-mapping></web-app>

依赖引入:

<!--添加servlet依赖-->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope>
</dependency>
<!--添加springmvc的依赖-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.0.8.RELEASE</version>
</dependency>
方法一:(貌似是不推荐使用,不太确定)

springmvc-servlet.xml

###springmvc的配置文件,对每一个springmvc控制器都需要配置bean标签

<?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"><!--配置一个视图解析器常用内部资源视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" ><!--1、前缀--><property name="prefix" value="/jsp/" /><!--2、后缀--><property name="suffix" value=".jsp" /></bean><bean class="com.xuzhi.controller.HelloController" name="/helloController" ></bean>
</beans>

HelloController.java

###控制器,类似于struts的action

package com.xuzhi.controller;import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;//实现一个Controller接口的方式
public class HelloController implements Controller {@Overridepublic ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {ModelAndView modelAndView=new ModelAndView();modelAndView.addObject("hello","Hello World!");modelAndView.setViewName("hello");return modelAndView;}
}

hello.jsp

###视图代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body>Happy New Year:${hello}
</body>
</html>

SpringMVC分析

组件分析

web.xml

注册前端控制器,目的在于,我们希望让springmvc去处理所有的请求

通过

<!--servlet映射配置-->
<servlet-mapping><servlet-name>springmvc</servlet-name><!--统一写“/”--><url-pattern>/</url-pattern>
</servlet-mapping>

确实是处理所有的请求(不是真的所有)

url-pattern的写法问题

  • / =>(推荐使用)

    • 处理所有的请求,但是和/*不一样,他处理完之后要出去的时候不会再去将这个hello.jsp当做一个新的请求,而是将这个渲染的结构直接返回给浏览器
  • /* =>(永远都不要这么写)

    • 不能写的原因:请求/helloController过去的时候,他的视图名称是hello,hello.jsp页面,他将其当做了一个叫hello.jsp的请求,尝试去匹配对应的Controller,但是我的容器当中根本不存在这样的controller,所以无法匹配,导致404
  • *.do

    • 这种方式,有的开发团队习惯将请求的行为加个小尾巴用以区分,.do,.action

关于前端控制器的解释

springmvc设计的理念是希望开发者尽量远离原生的servletAPI,API不是很好用,有些繁琐,将操作进一步的简化,他将很多东西责任进行了拆分,不希望我们将一些技术点绑定死,可以做到随意的切换。本身还是基于servlet设计的,分发的servlet,

springmvc配置文件名字的问题

默认情况下是dispatcherServlet的名字当做命名空间

[ServletName]-servlet.xml (WEB-INF)

servletName-servlet.xml = namespace.xml

之下寻找

降配置文件移动位置之后,出现了相应的错误

如果非要重新使用另外一个名字,可以使用

<!--可以使用init-param标签重新修改命名空间,在web-inf文件里可以使用mvc.xml文件,而不必一定使用springmvc-servlet.xml文件-->
<init-param><param-name>namespace</param-name><param-value>mvc</param-value>
</init-param>

默认的规则要求在web-inf下,但是maven项目的标准应该在resources下面,解决方案:

重新指定上下文的配置文件的位置即可

<init-param><!--上下文配置的位置的指定此时是在类路径下寻找springmvc-servlet.xml的配置文件配置文件的名称可以根据自己的要求命名--><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>

视图解析器

springmvc支持多种视图技术

  • jsp
  • freemaker

内部的资源视图解析器

  • 视图前缀

    • /jsp/他是我们的请求相应的资源的路径的配置, viewName:hello /jsp/hello
  • 视图后缀
    • .jsp 此时我们的前缀+视图名称+后缀 =/jsp/hello.jsp

解析器的作用类似于

request.getDispatcherServlet.forward(request,response);

物理视图是由逻辑视图转换而来

物理视图是webapp/jsp/hello.jsp

逻辑视图 p View =prefix + logicViewName + suffix

  • prefix => 前缀
  • logicViewName =>视图名称(在Controller中的ModelAndView的setViewName()方法来指定)
  • suffix =>后缀

控制器

是一种比较传统的实现一个接口的方式完成的,Controller

如果一个接口只有一个方法,这种接口叫做函数式接口

###ModelAndView方法是Controller接口内的唯一的一个方法,故Controller为函数式接口

@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest,                                    HttpServletResponse httpServletResponse) throws Exception {}

该代码类似于servlet里面由doGet doPost里面入参就是请求与相应。

在springmvc中,在model当中填充数据,然后在具体的视图进行展示

还需要在配置文件当中配置一下bean,这个bean要取个名字,就用来充当这个URI,他就处理一个请求,跟servlet的差别不是很大。

注解开发模式(方法二:推荐使用)

基于实现接口的方式已经是过去式了,采用注解开发很简单

基本注解
  • @Controller

  • @RequestMapping

    • 可以写在方法上
    • 也可以写在类上

    ###推荐使用二者结合的方式

    组合使用实例

    @Controller
    @RequestMapping("/bye")
    public class ByeController {//要想访问该Controller具体的地址应该是":8080/bye/bye"@RequestMapping("/bye")public String bye(Model model){model.addAttribute("hello","我的世界");//返回的为viewName,即视图的名字,此时寻找视图的路径为 /jsp/hello.jspreturn "hello";}
    }
    

    ###使用联合方式,第一个/bye可以区分大类,第二个/bye直接调用该具体Controller

springmvc-servlet.xml

###需要添加相应的命名空间,以使用Context

<!--配置一个注解扫描的包-->
<context:component-scan base-package="com.xuzhi.controller" />
<!--配置一个视图解析器常用内部资源视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" ><!--1、前缀--><property name="prefix" value="/jsp/" /><!--2、后缀--><property name="suffix" value=".jsp" />
</bean>
Controller.java
package com.xuzhi.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
//使用注解需要在springmvc的配置文件里面导入一个包,以启动注解扫描
//不需要继承任何的类也不需要实现任何的接口
@Controller
public class ByeController {@RequestMappingpublic String bye(Model model){//往view层传值model.addAttribute("hello","我的世界");//返回的为viewName,即视图的名字,此时寻找视图的路径为 /jsp/hello.jspreturn "hello";}
}
注解开发步骤总结:

1、配置基础扫描的包,这样配置的注解才会生效

2、在指定的类上面添加@Controller注解

3、在Controller类的方法前添加@RequestMapping注解,类似于前面的Controller的那个名字(不同requesthandler处理的handlerMapping)

当我们写上Controller之后,就标记了它为spring的一个组件,并且是控制器的组件,此时我们的handlermapping会去扫描寻找这个controller是否与之匹配,如果发现匹配就把这里处理的工作交给它

匹配的规则:

具体的匹配就是通过请求的路径进行匹配的

@RequestMapping(URI)

此时就是通过这个URI进行匹配

转发与重定向

转发

//请求
@RequestMapping("/forward")
public String forward(Model model){//springmvc model默认是在请求域中存储值System.out.println("请求");model.addAttribute("skill","请求测试");return "forward";
}

重定向

//重定向
@RequestMapping("/redirect")
public String redirect(Model model){model.addAttribute("skill","重定向测试");System.out.println("重定向");//重定向是需要在return的内容中增加重定向的标识=>“redirect:”+重定向视图的路径return "redirect:/jsp/redirect.jsp";
}
  • 转发到页面 (默认)

  • 重定向到页面 redirect:path

  • 转发到另外一个控制器 forward:path

关于springmvc访问web元素

  • request

  • session

  • application

可以通过模拟的对象完成操作,也可以使用原生的servletAPI完成,直接在方法当中入参即可

package com.xuzhi.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.WebRequest;import javax.servlet.http.HttpSession;@Controller
@RequestMapping("/web")
public class WebElementController {//request元素@RequestMapping("request")public String request(WebRequest request){System.out.println(request.getParameter("test"));return "forward";}//session元素@RequestMapping("session")public String session(HttpSession session){session.setAttribute("test","我是你爸爸");return "forward";}//application元素@RequestMapping("application")public String application(HttpSession session){//获取application并设置testsession.getServletContext().setAttribute("application","application测试");return "redirect:/jsp/forward.jsp";}
}

注解详解

@RequestMapping
  • value 写的是路径,是一个数组的形式,可以匹配多个路径

  • path 是value的别名,所以二者人选其一,他们的作用是一样的

  • method 指定可以访问的请求的类型,比如post,get,他也可以写成一个数组的形式

  • params 可以指定参数,还可以去限定这个参数的特征,比如等于某个值

    • params={“girl=a”,“boy!=b”} =>当请求的参数girl等于a,boy不等于b的时候才能继续向下执行
  • headers 能够影响浏览器的行为

  • consumers 消费者,媒体类型,可以限定为application.json;charset=UTF-8

  • produces 产生的响应的类型

    //请求映射的路径path可以有多个值,即请求这个controller可以用多个名字,m1,m2都可以请求这个          Controller
    //    @RequestMapping(value = {"/m1","/m2"})
    //    @RequestMapping(path = {"/m1","/m2"})
    //该请求只能接受post提交的表单
    @RequestMapping(path = {"/m1","/m2"},method = RequestMethod.POST)
    public String m1(Model model){model.addAttribute("annotations","@RequestMapping注解");return "annotations";
    }//用以处理post请求,参数为两个,分别为a和b
    @RequestMapping(path = "/m2",method = RequestMethod.GET,params = {"a","b"})
    public String m2(@RequestParam("a")Integer a, @RequestParam("b") Integer b){System.out.println(a+b);return "annotations";
    }
    
@GetMapping,@PostMapping…

​ 相等于RequestMapping中的method指定为get或者post,只能相应处理get或者post请求

@PathVariable

resultful风格

###请求时的url可以写成=》/product/add/产品id/产品名称/产品价格

​ 该Controller可以自动接收通过url传入的参数

@Controller
@RequestMapping("/product")
public class ProductController {@RequestMapping("/add/{id}/{name}/{price}")public String addProduct(@PathVariable("id")Integer id,@PathVariable("name")String                                              name,@PathVariable("price")Double price){System.out.println(id+name+price);return "forward";}
}

对于非get,post请求的支持 // TODO

对于非get,post请求的支持,需要有额外的内容添加,要增加一个过滤器来额外处理

他返回的不是页面,而是数据

  • DeleteMapping

  • PutMapping

  • 过滤器

    <!--注册一个支持所有http请求的过滤器--><filter><filter-name>hiddenHttpMethodFilter</filter-name><filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class></filter><filter-mapping><filter-name>hiddenHttpMethodFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
    
  • 表单提交里面还要添加一个隐藏的参数

    <form action="${ctx}/test/m2" method="post"><input type="hidden" name="_method" value="delete"><input type="submit" value="delete请求">
    </form>
    

@PutMapping

关于获取项目名称的问题

@WebServlet(urlPatterns = {},loadOnStartup = 2)
public class WebPathInitServlet extends HttpServlet {@Overridepublic void init(ServletConfig config) throws ServletException {//在整体应用上下文当中存储了一个ctx的值,用他来引用上下文路径config.getServletContext().setAttribute("ctx",config.getServletContext().getContextPath());super.init(config);}
}

###在jsp页面中需要全局项目名称时只需要引用${ctx},在此后的访问静态资源时会使用

关于请求路径的问题

springmvc支持ant风格

  • ?任意的字符

  • “*” 0到n,任意个字符都可以,/除外

  • ** 支持任意层路径,

    //    访问地址可以写为"/test/m3"+"任意单个字符,/除外"
    //    @RequestMapping(path = "/m3?")
    //    访问地址可以写为"/test/m3"+"可以放任意长度的字符串,但是不能包括/"
    //    @RequestMapping(path = "m3*")
    //    访问地址可以写为"/m3"+"/a"+"/b",可以有多层路径@RequestMapping(path = "m3/**")public String m3(){System.out.println("m3....");return "annotations";}
    

关于静态资源访问的问题

由于我们的servlet设置了URL匹配方式为/,所以,他将静态资源也当做一个后台的请求,

比如http://localhost:8080/SpringMVC/static/css/index.css

他尝试去匹配一个static/css/index.css的Controller里面的requestMapping的组合,因为没有,所以404,解决方式很多,最简单的,是让springmvc单独处理,将这些交给容器的默认的servlet处理,就不让DispatcherServlet来处理了

解决方式一(推荐使用这种方式,当需要引用的文件不能被识别时,可以增加第二种方式来引入)

<!--在springmvc的配置文件中添加-->
<!--默认的servlet处理者,必须同时添加两条mvc标签,否则会使所有的mvc注解失效-->
<mvc:default-servlet-handler />
<mvc:annotation-driven />

解决方式二

<mvc:resources mapping="static/css/*" location="static/css/" />

关于post请求中文乱码问题的解决

添加一个过滤器即可,springmvc提供了非常好的字符编码过滤器,所以我们注册即可

在web.xml中添加这样的配置进行注册(最好是放在servlet过滤器之前)

<!--注册一个处理中文乱码的过滤器,该过滤器是springmvc封装好的过滤器-->
<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><init-param><param-name>forceRequestEncoding</param-name><param-value>true</param-value></init-param>
</filter>
<filter-mapping><filter-name>characterEncodingFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

关于form表单提交数据的方式

方式一 通过属性名绑定

通过属性名称进行绑定,可以完成数据绑定

页面当中表单元素的name值要和后台的形参的名字保持一致。

如果有多个,多个形参按名字绑定即可,当传入的值校对的时候,会比较麻烦

<form action="${ctx}/user/put" method="post"><input type="hidden" name="_method" value="PUT"><input type="text" name="name"><input type="submit" value="put测试">
</form>
@PutMapping("put")
@ResponseBody
//形参要与前台页面传过来的name名称相对应
public String put(String name){System.out.println(name);return "@PutMapping测试成功";
}
方式二 利用@RequestParam注解

jsp页面不变

后台

@PutMapping("put")
@ResponseBody
public String put1(@RequestParam("name") String name){System.out.println(name);return "@PutMapping测试成功";
}
方式三 直接使用pojo形式传递

jsp页面一致

@PutMapping("/put2")
@ResponseBody
public String put2(User user){System.out.println(user.getName()+user.getPassword());return "@PutMapping测试成功";
}

关于form表单提交日期格式数据问题的处理

1、处理日期(没有时间)
@InitBinder("user")
public void init(WebDataBinder webDataBinder){SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");sdf.setLenient(false);webDataBinder.registerCustomEditor(Date.class,new CustomDateEditor(sdf,false));
}
@PostMapping("/model3")
public String model3(@ModelAttribute("user") User user){System.out.println(user.getName()+user.getPassword());System.out.println(user.getBirth());return "msg";
}
//通过initBinder指定了user名字和modelAttribute里面的user绑定

2、不指定名字,根据数据类型一样可以分析解析转换成功

@InitBinder()
public void init(WebDataBinder webDataBinder){SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");sdf.setLenient(false);webDataBinder.registerCustomEditor(Date.class,new CustomDateEditor(sdf,false));
}
@PostMapping("/model3")
public String model3(@ModelAttribute() User user){System.out.println(user.getName()+user.getPassword());System.out.println(user.getBirth());return "msg";
}

3、时间+日期的处理(推荐使用注解方式)

//通过Java源码的方式(如1、2),解决方案不是很理想,只能处理固定格式的时间日期格式,个人建议使用注解的方式来解决    比较好
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birth;

注解补充

@ResponseBody

返回数据,一般情况下返回json格式,需要引用json包

put.jsp =>put请求方式为例

<form action="${ctx}/user/put" method="post"><input type="hidden" name="_method" value="PUT"><input type="text" name="name"><input type="submit" value="put测试">
</form>

UserController.java

@Controller
@RequestMapping("/user")
public class UserController {//相应put请求@PutMapping("put")//表示将返回一个数据结果,而不是页面@ResponseBodypublic String put(String name){System.out.println(name);//返回数据,为测试方便,结果返回一个String字符串return "@PutMapping测试成功";}
}
@ModelAttribute

使用方式一:

//就是在controller里面的任意一个处理具体的方法之前执行
@ModelAttribute
public User init(){User u=new User();u.setName("王是你爸爸");return u;
}
@RequestMapping("/model")
public String model(Model model){//判断init()方法是否在该方法之前执行,即判断init()方法是否返回了User对象,同时确定了          init()返回的对象名是什么System.out.println(model.containsAttribute("user"));System.out.println(model.addAttribute("user"));return "msg";
}

如果某些对象从头到尾每次请求当中都要存在,不消失,就适合使用这种方法。

使用方式二

//就是在controller里面的任意一个处理具体的方法之前执行
@ModelAttribute
public void init(Model model){User u=new User();u.setName("王是你爸爸");model.addAttribute("user",u);
}
@RequestMapping("/model")
public String model(Model model){//判断init()方法是否在该方法之前执行,即判断init()方法是否返回了User对象,同时确定了init()返回的对象名是什么System.out.println(model.containsAttribute("user"));System.out.println(model.addAttribute("user"));return "msg";
}

使用方式三:

//如果前台没有传过来相应的值,使用该注解后会自动去我们的model模型中寻找相应的user,
//如果前台传值过来,则init()方法返回的内容则由前台穿过来的model模型替换
@RequestMapping("/model2")
public String model2(@ModelAttribute User user){System.out.println(user.getName()+user.getPassword());return "msg";
}
@InitBinder
@DateTimeFormat

用以标记处理springmvc的中传值时间日期问题,格式化时间日期

@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birth;
@RequestBody

json数据,不是通过form表单传递

ajax({data:
})
@SessionAttributes
@Controller
@RequestMapping("/user3")
@SessionAttributes("user")
public class User3Controller {@PostMapping("/session")public String session(User user){return "redirect:/jsp/user.jsp";}
}
@SessionAttribute

要求当前这次访问当中的会话当中必须有某个对象,简而言之,@SessionAttributes是往会话中添加某个模型数据,而@SessionAttribute是为了检查当前会话中是否有需要检测的模型数据

@RestController

@RestController=@Controller+@ResponseBody

该注解标记的Controller类可以指定该Controller类中的所有方法都返回数据,而不是返回页面

JSON数据交互

添加相关依赖

<!--添加JSON的相关依赖-->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.9.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.9.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
<dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>2.4</version><classifier>jdk15</classifier>
</dependency>
<!--添加将JSON处理为JavaBean的依赖-->
<!-- https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-core-asl -->
<dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-core-asl</artifactId><version>1.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-mapper-asl -->
<dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-mapper-asl</artifactId><version>1.9.2</version>
</dependency>
<!--添加将JSON处理为JavaBean的依赖 =>end -->

JSON如何返回前台

1、返回一个pojo
//返回一个pojo
@RequestMapping("/m1")
@ResponseBody  //这个注解将制定返回的不是视图,而是数据,他会将我们的返回数据格式转换为json数据格式
public User json1(){User user=new User();user.setName("我是你爸爸");user.setPassword("root");return user;
}
2、返回一个Map
//返回一个Map
@RequestMapping("/m2")
@ResponseBody  //这个注解将制定返回的不是视图,而是数据,他会将我们的返回数据格式转换为json数据格式
public Map<String,Object> json2(){Map<String,Object> map=new HashMap<>();map.put("name","你爸爸就是你爸爸");map.put("age",21);return map;
}
3、返回一个数组
@RequestMapping("/m3")
@ResponseBody
public User[] json3(){User user1=new User();user1.setName("我是你爸爸1");user1.setPassword("你爸爸");User user2=new User();user2.setName("你爸爸就是你爸爸");user2.setPassword("你就是你");return new User[]{user1,user2};
}
4、返回一个list
@RequestMapping("/m4")
@ResponseBody
public List<User> json4(){List<User> list=new ArrayList<>();User user1=new User();user1.setName("我是你爸爸");user1.setPassword("你爸爸");User user2=new User();user2.setName("你爸爸就是你爸爸");user2.setPassword("你就是你");list.add(user1);list.add(user2);return list;
}

JSON如何在前台解析

1、解析返回的pojo
$.ajax({url:'${ctx}/json/m1',type:'post',success:function (data) {alert(data.name);alert(data.password);}
})
2、解析返回的map
//接收返回的map
$('#map').click(function () {$.ajax({url:'${ctx}/json/m2',type:'post',success:function (data) {alert(data.name);alert(data.age);}})
})
3、解析返回的数组
//接收返回的数组
$('#array').click(function () {$.ajax({url:'${ctx}/json/m3',type:'post',success:function (data) {for(var i=0;i<data.length;i++){alert(data[i].name);alert(data[i].password);}}})
})
4、解析返回的list
//接收返回的数组
$('#list').click(function () {$.ajax({url:'${ctx}/json/m4',type:'post',success:function (data) {for(var i=0;i<data.length;i++){alert(data[i].name);alert(data[i].password);}}})
})

JSON如何将数据传到后台

必须要添加,来规范传输json数据格式以及编码标准

contentType:"application/json;charset=utf-8"
1、前台ajax向后台发送一个pojo
$('#user').click(function () {var obj={"name":"我是你爸爸","password":"你爸爸就是你爸爸"};$.ajax({url:'${ctx}/json2/add',type:'post',contentType:'application/json',data:JSON.stringify(obj),success:function (data) {}})
})
//前台提交一个user过来
@RequestMapping("/add")
//User user入参只能处理form表单提交的数据
//要想接收前台ajax发过来的json数据,需在入参时添加@RequestBody注解
public String add(@RequestBody User user){System.out.println(user.getName()+user.getPassword());return "msg";
}
2、前台ajax向后台发送一组pojo
$('#userList').click(function () {var obj={"name":"我是你爸爸","password":"你爸爸就是你爸爸"};var obj2={"name":"我是你爷爷","password":"你爷爷就是你爷爷"};var array=new Array();array.push(obj);array.push(obj2);$.ajax({url:'${ctx}/json2/addList',type:'post',contentType:'application/json',data:JSON.stringify(array),success:function (data) {if(data.code==2000){alert("测试成功");}}})
})
//前台提交一个user过来
@RequestMapping("/addList")
//User user入参只能处理form表单提交的数据
//要想接收前台ajax发过来的json数据,需在入参时添加@RequestBody注解
@ResponseBody
public Map<String,Integer> addList(@RequestBody List<User> user){Map<String,Integer> map=new HashMap<>();map.put("code",2000);System.out.println(user);return map;
}

XML数据交互

对于很多第三方开发,还是有很多会采用xml作为数据交互,比如微信

添加额外依赖
<!--添加xml解析的依赖-->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><version>2.9.3</version>
</dependency>a
方法测试

##仅作为小测试,需要用时自行查阅

//produces用于指定返回数据的数据类型,在这里我们指定为XML格式
@RequestMapping(value = "/m1",produces = MediaType.APPLICATION_ATOM_XML_VALUE)
@ResponseBody
public User m1(){User user=new User();user.setName("我是你爸爸");user.setPassword("你爸爸就是你爸爸");return user;
}

文件上传与下载

文件上传

方式一:Apache Upload文件上传方式

1、添加相关依赖

<!--Apache文件上传组件-->
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.3</version>
</dependency>

2、在springmvc的配置文件中注册一个文件上传解析器

<!--注册文件上传解析器id的必须为multipartResolver,因为源代码中写死了这个名字,不可更改
-->
<bean id="multipartResolver"                                                          class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!--定义上传的所有文件的总上传大小的最大值,单位为bytes--><property name="maxUploadSize" value="1048576" /><!--指定上传文件的编码方式--><property name="defaultEncoding" value="UTF-8" /><!--指定上传的单个文件的最大上传大小,单位为bytes--><property name="maxUploadSizePerFile" value="1024" />
</bean>

3、准备一个上传的页面

<%--要实现文件上传,必须要添加enctype="multipart/form-data" --%>
<form action="${ctx}/file/upload" method="post" enctype="multipart/form-data">文件:<input type="file" name="upload"><br><input type="submit" value="文件上传">
</form>

4、后台处理程序

@Controller
@RequestMapping("/file")
public class FileController {private static String uploadPath="I:/newFile/";/*** 文件上传要处理的问题* 1、传到哪里去;2、要传什么东西;3、文件传输的细节* @param multipartFile* @return*/@RequestMapping("/upload")public String upload(@RequestParam("upload")MultipartFile multipartFile, Model model){//1、判断上传的文件是否为空if(multipartFile!=null && !multipartFile.isEmpty()){//2、获取上传文件的原始文件名String originalFilename = multipartFile.getOriginalFilename();//3、截取源文件名的前缀,不带后缀String fileNamePrefix=originalFilename.substring(0,originalFilename.lastIndexOf("."));//4、加工处理原文件名,原文件名+时间戳String newFileNameProfix=fileNamePrefix+new Date().getTime();//5、得到新的文件名String newFileName=newFileNameProfix+originalFilename.substring(originalFilename.lastIndexOf("."));//6、构建文件对象File file =new File(uploadPath+newFileName);//7、上传try {multipartFile.transferTo(file);model.addAttribute("fileName",newFileName);} catch (IOException e) {e.printStackTrace();}}return "success";}
}

文件下载

@Controller
@RequestMapping("/download")
public class DownloadController {//定义一个文件下载的路径private static String DownloadPath="I:/newFile/";//@RequestMapping("/down")public String download(HttpServletResponse response){//通过输出流写入到客户端//1、获取文件下载名String fileName="typora-setup-x64.exe";//2、构建一个文件对象通过Paths工具类获取一个Path对象Path path = Paths.get(DownloadPath, fileName);//3、判断文件是否存在if(Files.exists(path)){//存在则此下载//通过response设定它响应的类型//4、获取文件的后缀,即获取文件的类型String fileSuffix=fileName.substring(fileName.lastIndexOf(".")+1);//5、设置contentType,只有指定他才能下载文件response.setContentType("application/"+fileSuffix);//6、添加头信息//因为是springmvc只能处理ISO8859-1,所以要将文件名通过UTF-8提取出字节流名称再转换成标                  准的ISO8859-1try {response.setHeader("Content-Disposition","attachment;filename="+new String(fileName.getBytes("UTF-8"),"ISO8859-1"));} catch (UnsupportedEncodingException e) {e.printStackTrace();}//7、通过path写出该文件try {Files.copy(path,response.getOutputStream());} catch (IOException e) {e.printStackTrace();}}return "success";}
}

拦截器

springmvc提供了拦截器,类似于过滤器,他将在我们的请求距离之前先做检查,有权决定,接下来是否继续,对我们的请求进行加工。拦截器,可以设计多个,

通过实现HandlerIntercepror,这是一个接口,定义了三个非常重要的方法

  • 前置处理
  • 后置处理
  • 完成处理

案例一,运行时间计算与好坏判断

后台代码

package com.xuzhi.interceptors;import org.apache.log4j.Logger;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 方法耗时统计的拦截器*/
public class MethodTimerInterceptor implements HandlerInterceptor {private static final Logger LOGGER=Logger.getLogger(MethodTimerInterceptor.class);//前置功能 开始到结束,计算两个点之间所需要的时间@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1、定义开始时间long start=System.currentTimeMillis();//2、将开始时间存到请求域当中request.setAttribute("start",start);//记录请求日志LOGGER.info(request.getRequestURI()+"请求到达!");//返回true,才会去找下一个拦截器,如果没有下一个拦截器,则去到Controller执行请求return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {//1、得到开始的时间long start= (long) request.getAttribute("start");//2、得到结束的时间long end=System.currentTimeMillis();//3、计算耗时long speedTime=end-start;if(speedTime>=1000){LOGGER.warn("请求耗时严重,耗时:"+speedTime+"毫秒");}else{LOGGER.info("请求耗时正常,耗时:"+speedTime+"毫秒");}}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

配置文件

<mvc:interceptor><!--/**/*  拦截所有的请求/*    只拦截单层路径的请求--><mvc:mapping path="/**/*"/><bean class="com.xuzhi.interceptors.MethodTimerInterceptor" />
</mvc:interceptor>

案例二:Session拦截器

后台代码

package com.xuzhi.interceptors;import com.xuzhi.pojo.User;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 会话拦截器*/
public class SessionInterceptor implements HandlerInterceptor {private static final Logger LOGGER=Logger.getLogger(SessionInterceptor.class);//检查当前会话是不是有该User,如果有,放行,如果没有,则拦截@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//获取会话中的User对象Object user=request.getSession().getAttribute("SESSION_USER");//判断该用户是否登录,if(user == null){LOGGER.warn("您不具备该权限,请先登录");return false;}//先判断user是否为空,即判断用户是不是登录//如果用户登录,则判断用户是不是User类型if(user instanceof User){//去数据库检测该用户是否存在,给予该用户冻结状态,密码附空User u= (User) user;u.setPassword(null);request.getSession().setAttribute("SESSION_USER",u);LOGGER.info(u.getName()+"登录状态");return true;}else{LOGGER.warn("请先登录,不要搞事情");return false;}}
}

配置文件

<mvc:interceptor><!--只想拦截/user/**/*还需要开放登录权限--><mvc:mapping path="/user/**/*"/><mvc:exclude-mapping path="/user/login" /><bean class="com.xuzhi.interceptors.SessionInterceptor"></bean>
</mvc:interceptor>

拦截器执行顺序的问题

如果有n个拦截器,并且都能拦截到某个URI的时候,执行顺序问题,

在springmvc中当中拦截器定义的先后顺序有关系,配置在前面的优先执行,按照顺序来

例如:有三个拦截器 i1.i2.i3

前置处理顺序:i1,i2,i3

后置处理顺序:i3,i2,i1

拦截器与过滤器的比较

  • 相似:都有优先处理请求处理的权利,可以决定是否将请求转移到实际处理的控制器处,都可以对请求或者会话当中的数据进行加工
  • 不同:
    • 拦截器可以做前置处理,也可以做后置处理,还可以完成后处理,控制更加细一些,过滤器只负责前面的过滤的行为而已
    • 过滤器优先执行
    • 过滤器是servlet规范里面的组件
    • 拦截器都是框架自己额外添加的组件

SSM整合

spring和springmvc是天然集成,所以只需要解决mybatis和spring整合的问题,中间项目mybatis-spring项目进行整合

  • 由spring容器管理mybatis这个mapper
  • 由spring利用声明式事务(AOP)进行事务综合管理

添加依赖

<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope>
</dependency>
<!--添加servlet,jsp,jstl相关依赖 ==============start=================-->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency><groupId>javax.servlet.jsp</groupId><artifactId>javax.servlet.jsp-api</artifactId><version>2.3.1</version><scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version>
</dependency>
<!--添加servlet,jsp,jstl相关依赖 ==============end=================-->
<!--spring相关依赖,包括springmvc  ===============start===============-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.0.8.RELEASE</version>
</dependency>
<!--利用他来处理事务问题-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.0.8.RELEASE</version>
</dependency>
<!--springmvc-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.0.8.RELEASE</version>
</dependency>
<!--spring =======================spring end==========================-->
<!--持久层依赖 ====================start===================================-->
<!--mybatis框架相关依赖-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.6</version>
</dependency>
<!--mysql数据库连接驱动相关依赖-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version>
</dependency>
<!--持久层依赖 ===========================end==============================-->
<!--添加JSON的相关依赖-->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.9.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.9.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
<dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>2.4</version><classifier>jdk15</classifier>
</dependency>
<!--添加将JSON处理为JavaBean的依赖-->
<!-- https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-core-asl -->
<dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-core-asl</artifactId><version>1.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-mapper-asl -->
<dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-mapper-asl</artifactId><version>1.9.2</version>
</dependency>
<!--json===============================================end======-->
<!--添加文件上传所需要的依赖=====================start========================-->
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.3</version>
</dependency>
<!--添加文件上传所需要的依赖=====================end========================-->
<!--添加xml解析的依赖-->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><version>2.9.3</version>
</dependency>
<!--日志输出 =================================start================================================-->
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.2</version><scope>test</scope>
</dependency>
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
<!--日志打印 ==================================end====================================================-->
<!--数据源的引入,池化技术 ======================start==================================-->
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.2.1</version>
</dependency>
<!--数据源的引入 ======================end==================================-->
<!--mybatis与spring整合需要的依赖 =================strat==========================-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.0</version>
</dependency>
<!--mybatis与spring整合需要的依赖 =================end==========================-->
<!--处理时间日期的依赖===================start====================-->
<!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
<dependency><groupId>joda-time</groupId><artifactId>joda-time</artifactId><version>2.9.9</version>
</dependency>
<!--处理时间日期的依赖===================end====================-->
<!--mybatis分页依赖====================start==========================-->
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.2</version>
</dependency>
<!--mybatis分页依赖====================end==========================-->
<!--apache MD5加密 ====================start=============================-->
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.10</version>
</dependency>
<!--apache MD5加密 ====================end=============================-->

web.xml配置

注册spring的上下文文件
<!--注册一个spring的上下文文件-->
<context-param><!--指定上下文配置文件路径--><param-name>contextConfigLocation</param-name><param-value>classpath:/spring/applicationContext.xml</param-value>
</context-param>
字符编码以及全HTTP请求支持过滤器添加
<!--注册一个处理中文乱码的过滤器,该过滤器是springmvc封装好的过滤器-->
<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><init-param><param-name>forceRequestEncoding</param-name><param-value>true</param-value></init-param><init-param><param-name>forceResponseEncoding</param-name><param-value>true</param-value></init-param>
</filter>
<filter-mapping><filter-name>characterEncodingFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
<!--注册一个支持所有http请求的过滤器-->
<filter><filter-name>hiddenHttpMethodFilter</filter-name><filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping><filter-name>hiddenHttpMethodFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
DispatcherServlet注册
<!--注册一个前端控制器-->
<servlet><!--如果我们不去修改spring配置文件默认的位置,那么springmvc会去web-inf路径下的springmvc-servlet.xml文件--><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--可以使用init-param标签重新修改命名空间,在web-inf文件里可以使用mvc-servlet.xml文件,而不必一定使用springmvc-servlet.xml文件--><!--<init-param>--><!--<param-name>namespace</param-name>--><!--<param-value>mvc</param-value>--><!--</init-param>--><init-param><!--上下文配置的位置的指定配置文件的名称可以根据自己的要求命名--><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param>
</servlet>
<!--servlet映射配置-->
<servlet-mapping><servlet-name>springmvc</servlet-name><!--统一写“/”--><url-pattern>/</url-pattern>
</servlet-mapping>
spring启动监听器配置
<!-- spring容器生命周期监听器配置 -->
<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

spring核心配置文件编写

核心配置文件用于引入其他配置文件

applicationContext.xml
<?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"><!--引入spring和其他整合的配置文件--><import resource="classpath:spring/spring-*.xml"/>
</beans>
spring-servlet.xml
<?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:c="http://www.springframework.org/schema/c"xmlns:cache="http://www.springframework.org/schema/cache"xmlns:context="http://www.springframework.org/schema/context"xmlns:jdbc="http://www.springframework.org/schema/jdbc"xmlns:jee="http://www.springframework.org/schema/jee"xmlns:lang="http://www.springframework.org/schema/lang"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:p="http://www.springframework.org/schema/p"xmlns:task="http://www.springframework.org/schema/task"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsdhttp://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsdhttp://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.3.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.3.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd "><!--启动注解排除了Service注解--><context:component-scan base-package="com.xuzhi" ><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"  /></context:component-scan><!--配置一个视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/pages/" /><property name="suffix" value=".jsp" /></bean><!--静态资源处理--><mvc:default-servlet-handler /><!--添加MVC驱动--><mvc:annotation-driven><!--配置消息转换器以支持JSON的使用--><mvc:message-converters><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes"><list><value>application/json;charset=UTF-8</value></list></property></bean></mvc:message-converters></mvc:annotation-driven><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><property name="messageConverters"><list><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes" ><list><value>text/html;charset=UTF-8</value></list></property></bean><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/html;charset=UTF-8</value><value>application/json;charset=UTF-8</value></list></property></bean></list></property></bean><!--文件上传id必须取名为multipartResolver,注册我们的文件上传解析器--><!--注册文件上传解析器id的必须为multipartResolver,因为源代码中写死了这个名字,不可更改--><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!--定义上传的所有文件的总上传大小的最大值,单位为bytes--><property name="maxUploadSize" value="1073741824" /><!--指定上传文件的编码方式--><property name="defaultEncoding" value="UTF-8" /><!--指定上传的单个文件的最大上传大小,单位为bytes--><property name="maxUploadSizePerFile" value="4194304" /></bean></beans>
spring-mybatis.xml

整合ORM功能

<?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:c="http://www.springframework.org/schema/c"xmlns:cache="http://www.springframework.org/schema/cache"xmlns:context="http://www.springframework.org/schema/context"xmlns:jdbc="http://www.springframework.org/schema/jdbc"xmlns:jee="http://www.springframework.org/schema/jee"xmlns:lang="http://www.springframework.org/schema/lang"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:p="http://www.springframework.org/schema/p"xmlns:task="http://www.springframework.org/schema/task"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsdhttp://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsdhttp://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.3.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.3.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd "><context:component-scan base-package="com.xuzhi.mapper"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan><!--引入数据库想关信息的配置文件--><context:property-placeholder location="classpath:jdbc.properties" /><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${driver}" /><property name="jdbcUrl" value="${url}" /><property name="user" value="${username}" /><property name="password" value="${password}" /><!--如果有需要,请把所有的属性写到properties文件当中--><!--c3p0连接池的私有属性--><property name="maxPoolSize" value="30" /><property name="minPoolSize" value="10" /><!--关闭连接后不自动commit--><property name="autoCommitOnClose" value="false" /><!--获取连接超时时间--><property name="checkoutTimeout" value="100000" /><!--当前连接失败重试次数--><property name="acquireRetryAttempts" value="2" /></bean><!--最后关键一步,如何整合mybatis--><!--1、注入一个mybatis的SQLSessionFactory,这就是我们所要做的关键步骤,2、声明式的事务管理--><bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactoryBean" ><property name="dataSource" ref="dataSource" /><!--<property name="configLocation" value="classpath:mybatis.cfg.xml" />--><!--引入mapper文件--><!--这就要求所有的mapper文件必须在com/xuzhi/mapper/之下--><property name="mapperLocations" value="classpath:com/xuzhi/mapper/**/*.xml" /><property name="configLocation"><bean class="org.apache.ibatis.session.Configuration"><!--可以加入驼峰命名,其他mybatis的配置也就是mybatis.cfg.xml的相关配置都会转移到这里来--><property name="mapUnderscoreToCamelCase" value="true" /></bean></property><!--插件配置--><property name="plugins" ><array><!--分页插件的配置,拦截器实现分页功能--><bean class="com.github.pagehelper.PageInterceptor"><!--这里有几个配置主要演示如何使用,如果不理解,一定要去掉下面的配置--><property name="properties"><value>helperDialect=mysqlreasonable=truesupportMethodArguments=trueparams=count=countSqlautoRuntimeDialect=true</value></property></bean></array></property></bean><!--持久层接口--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.xuzhi.mapper" /><property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean" /></bean><!--事务管理,使用数据源事务管理类进行管理--><bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager"><property name="dataSource" value="dataSource" /></bean><!--确定事务管理的策略,transaction-manager:指向上面的transactionManage--><tx:advice transaction-manager="transactionManager" id="transactionAdvice"><!--事务处理的相关知识以及他的传播性--><tx:attributes><!--查询相关配置为只读,select,get,query开头--><tx:method name="select*" read-only="true"/><tx:method name="get*" read-only="true"/><tx:method name="query*" read-only="true"/><tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception" /><tx:method name="update*" propagation="REQUIRED" rollback-for="Exception" /><tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" /><tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception" /></tx:attributes></tx:advice><!--使用aop对事务管理的范围进行织入,明确几个点1、对那些地方需要进行事务的管理,execution书写,明确边界2、使用什么策略去管理,策略我们使用了tx:advice全部书写于其中,在我们的aop的advisor当中只需要引用这个事务管理者的建议即可--><aop:config><aop:pointcut id="txCut" expression="execution(* com.xuzhi.service..*.*(..))" /><aop:advisor advice-ref="transactionAdvice" pointcut-ref="txCut" /></aop:config><!--采用注解进行事务管理,请在Service的实现类上面加上@Transactional注解--><tx:annotation-driven transaction-manager="transactionManager" /></beans>
spring-context.xml
<?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:c="http://www.springframework.org/schema/c"xmlns:cache="http://www.springframework.org/schema/cache"xmlns:context="http://www.springframework.org/schema/context"xmlns:jdbc="http://www.springframework.org/schema/jdbc"xmlns:jee="http://www.springframework.org/schema/jee"xmlns:lang="http://www.springframework.org/schema/lang"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:p="http://www.springframework.org/schema/p"xmlns:task="http://www.springframework.org/schema/task"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsdhttp://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsdhttp://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.3.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.3.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd "><!--做spring的基础配置--><!--1、spring容器注册--><context:annotation-config /><!--2、自动扫描配置--><context:component-scan base-package="com.xuzhi" /><!--3、激活aop注解方式的代理--><aop:aspectj-autoproxy /><!--消息格式转换--><bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean" id="conversionService" ><property name="registerDefaultFormatters" value="false" /><property name="formatters"><set><bean class="org.springframework.format.number.NumberFormatAnnotationFormatterFactory" /></set></property><property name="formatterRegistrars"><set><bean class="org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar" ><property name="dateFormatter"><bean class="org.springframework.format.datetime.joda.DateTimeFormatterFactoryBean"><property name="pattern" value="yyyyMMdd" /></bean></property></bean></set></property></bean></beans>

SSM框架学习文档以及SSM整合(附Github地址=含SSM学习时的实例代码)相关推荐

  1. django框架学习文档_Python四大主流网络编程框架,你知道么?

    高并发处理框架-- Tornado Tornado 是使用 Python 编写的一个强大的可扩展的 Web 服务器.它在处理高网络流量时表现得足够强健,却在创建和编写时有着足够的轻量级,并能够被用在大 ...

  2. 安卓学习文档收集汇总

    安卓学习文档收集汇总 https://www.jianshu.com/p/86aed183ce6c?utm_campaign=maleskine&utm_content=note&ut ...

  3. 2w多字总结的VUE学习文档

    VUE学习文档 文章目录 VUE学习文档 回顾: 总结 0 目标 1.前言 2.认识Vue 3.快速入门 3.1.创建工程 3.2.安装vue 3.2.1.下载安装 3.2.2.使用CDN 3.3.v ...

  4. springboot学习文档

    SpringBoot学习文档 首先真的特别感谢同学的分享以及老师的整理,让我成功入门了springboot的. 一.介绍 小结: - SpringBoot并不是一个新的开发语言- Spring Boo ...

  5. FreeMarker中文帮助手册API文档,基础入门学习文档

    FreeMarker中文帮助手册API文档,基础入门学习文档 分类: 编程技术 发布: bywei 浏览: 7 日期: 2011年5月28日 分享到: QQ空间 新浪微博 腾讯微博 人人网 什么是Fr ...

  6. NodeJS-001-Nodejs学习文档整理(转-出自http://www.cnblogs.com/xucheng)

    Nodejs学习文档整理 http://www.cnblogs.com/xucheng/p/3988835.html 1.nodejs是什么: nodejs是一个是javascript能在后台运行的平 ...

  7. [扩展阅读] EasyGUI 学习文档【超详细中文版】

    [扩展阅读] EasyGUI 学习文档[超详细中文版] 0. 安装 EasyGUI 官网:https://github.com/robertlugg/easygui python查看内置的所有模块 h ...

  8. bootstrapt学习指南_Bootstrap学习文档(一)

    Boostrap中中文网 1. Bootstrap 是什么 Bootstrap 是最受欢迎的 HTML.CSS 和 JS 框架,用于开发响应式布局.移动设备优先的 WEB 项目,使用这个框架可以简单高 ...

  9. Hadoop大数据平台实践(二):Hadoop生态组件的学习文档

    Hadoop基础组件学习-Yzg-2019-03-06 Hadoop基础组件学习文档.. 1 简介.. 4 HDFS. 5 HDFS读文件.. 6 HDFS写文件.. 7 Mapreduce 8 单词 ...

最新文章

  1. [Cake] 1. CI中的Cake
  2. EUV光刻机全球出货量达57台
  3. vue sleep_vue不常用的知识点的整理
  4. linux 编译窗口,Ubuntu 10.04上编译安装Sawfish窗口管理器
  5. spi收发时的寄存器sr不变_「正点原子Linux连载」第二十七章SPI实验(二)
  6. redis-python操作redis
  7. Java性能分析点滴
  8. could not connect to server: No route to host Is the server running on host 192.168.163.181 and a
  9. AcWing 145.超市(二叉堆)
  10. 微信小程序 java家庭个人收支理财记账本springboot
  11. 一篇文章看懂NB-IoT
  12. Latex中使用实心圆点列表
  13. 阿里云ECS上使用docker搭建filebeat+kafka集群+zookeep集群+logstash+elasticsearch集群+kibana实现跨主机日志收集系统【四】
  14. 全面认识思科系列交换机型号
  15. python的pandas库的pd.read_excel()常用解析
  16. 表单写年龄选择html,表 单 / HTML
  17. 财务做账自动化生成系统
  18. 嵌入式linux之yocto(十)添加软件包菜谱
  19. 当群星游戏打开显示无法访问Documents库的解决方案
  20. 果园施药机具农业科研进展

热门文章

  1. 【千里之行,始于足下】大数据高频面试题——Hadoop篇(一)
  2. 使用c语言计算分期贷款折算年化收益率(内部收益率IRR*12)
  3. excel单元格下拉选项怎么设置_使用Excel制作搜索式下拉菜单,让你不再烦恼下拉选项多内容...
  4. ImportError: DLL load failed while importing win32api
  5. EasyRecovery 简体中文版
  6. 消除代码中的 if-else/switch-case的正确姿势
  7. multisim变压器反馈式_基于Multisim的负反馈放大电路仿真分析
  8. mysql总是出乱码怎么办_mysql数据库出现乱码怎么办
  9. 计算机相关美文摘抄,值得摘抄的好文章,好文章摘抄大全
  10. 轻松实现各种文档格式转换,doc转pdf、doc转png图片、pdf转png图片,可以实现Windows、Linux、MacOS平台上部署(附源码和说明)