1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > IDEA创建springboot项目

IDEA创建springboot项目

时间:2019-11-27 23:31:34

相关推荐

IDEA创建springboot项目

1、新建springboot项目

2、选择版本依赖

3、maven配置

4、yml文件配置

# YML文件的语法# 1.数据结构 key-value结构# 2.写法:key:(空格)value# 3.层级代码结构,注意缩进 !!!!!# 4.字符集 文件读取时,默认采用UTF-8编码 可以写中文# 规则: 命名时最好指定前缀.server:port: 8080mysql:username: rootpassword: root

5、动态为属性赋值,编辑JDBCController

/*** 说明:* 1.将该类交给Spring容器管理* 2.SpringMVC负责调用该对象接收用户的请求.* 3.将业务处理之后的结果,为页面返回JSON数据.* @ResponseBody作用: 将数据转化为JSON串*/@RestControllerpublic class JDBCController {//${key} Spring提供的springel表达式 简称为:spel表达式//语法: 从spring容器内部获取key,动态为属性赋值.@Value("${mysql.username}")String username;// = "root|";@Value("${mysql.password}")String password;// = "root";@RequestMapping("/getMsg")public String getMsg(){return "你好数据库:"+ username +password;}}

6、访问:http://localhost:8080/getMsg,浏览器页面显示

7、利用properties文件为属性赋值,编辑mysql.properties

#默认ISO-8859-1 中文必定乱码mysql.username2=mysql数据库mysql.password2=你猜猜

8、通过注解为属性赋值,可以指定字符集

/*** 说明:* 1.将该类交给Spring容器管理* 2.SpringMVC负责调用该对象接收用户的请求.* 3.将业务处理之后的结果,为页面返回JSON数据.* @ResponseBody作用: 将数据转化为JSON串** propertySource: value属性指定路径* encoding属性指定配置文件编码格式*/@RestController@PropertySource(value="classpath:/mysql.properties", encoding = "UTF-8")public class JDBCController {//${key} Spring提供的springel表达式 简称为:spel表达式//语法: 从spring容器内部获取key,动态为属性赋值.@Value("${mysql.username}")String username;// = "root|";@Value("${mysql.password}")String password;// = "root";@RequestMapping("/getMsg")public String getMsg(){return "你好数据库:"+ username +password;}/*** 难点: 如何将pro文件交给Spring容器管理????* 解决方案: @PropertySource("xxxxxx/xxx.properties") 指定配置文件交给Spring容器管理*/@Value("${mysql.username2}")private String username2;@Value("${mysql.password2}")private String password2;@RequestMapping("/getMsg2")public String getMsg2(){return "你好数据库:"+ username2 +password2;}}

9、访问:http://localhost:8080/getMsg2,浏览器页面显示

10、springboot高级用法,创建springboot项目

模板,maven

11、编辑pom.xml

<?xml version="1.0" encoding="UTF-8"?><project xmlns="/POM/4.0.0"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.jt</groupId><artifactId>springboot_demo2</artifactId><version>1.0-SNAPSHOT</version><!--只需要复制 除了坐标之外的文件即可--><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.4.1</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.4.1</version><configuration><mainClass>com.jt.SpringbootDemo1Application</mainClass></configuration><!--排除一些指定的配置--><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>

12、yml配置文件

开发 dev: 8080端口 生产 prod: 9000端口

#指定环境的默认配置spring:profiles:active: dev---#为环境定义名称server:port: 8080spring:config:activate:on-profile: dev# 采用---的方式实现环境分割---server:port: 9000spring:config:activate:on-profile: prod

13、热部署

在开发阶段,需要频繁的修改配置文件/代码

需求:要求将代码保存之后,程序自动的编译,并且完成tomcat服务的重启

个别IDEA版本可能不生效

<!--支持热部署 开发阶段有效--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency>

14、创建pojo,DemoUser

/*** 实体对象要求:*1.类名一般与表名关联*2.属性名称一般与字段关联*3.pojo中的属性类型必须为引用类型(包装类型)*4.实体对象必须有get/set方法*5.一般实体对象需要实现序列化接口(规则)*原因: 数据可能跨平台(跨服务器)传输,必须序列化*/public class DemoUser implements Serializable {private Integer id;private String name;private Integer age;private String sex;}

15、lombok依赖

lombok可以为POJO实体对象,动态的生成get/set/toString/hashcode/equals等方法,无需程序员手动编辑

<!--引入插件lombok 自动的set/get/构造方法插件 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>

16、采用注解

@Data //动态生成get/set/toString/equals等方法@Accessors(chain = true) //开启链式加载 重写set方法@NoArgsConstructor //无参构造@AllArgsConstructor //有参构造public class DemoUser implements Serializable {private Integer id;private String name;private Integer age;private String sex;//方法测试public void add(){DemoUser user = new DemoUser();user.setId(100).setName("aaaa").setAge(18).setSex("女");}}

17、Mybatis依赖

<!--mybatis依赖包--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version></dependency><!--jdbc依赖包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency>

18、编辑DemoUser

@Data //动态生成get/set/toString/equals等方法@Accessors(chain = true) //开启链式加载 重写set方法@NoArgsConstructor //无参构造@AllArgsConstructor //有参构造public class DemoUser implements Serializable {private Integer id;private String name;private Integer age;private String sex;}

19、编辑mybatis-config.xml文件

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-////DTD Config 3.0//EN""/dtd/mybatis-3-config.dtd"><!--核心配置文件--><configuration><!--环境配置标签 default 默认加载的环境 只能写一个 --><environments default="development"><!--编辑开发环境 id是环境唯一标识符 --><environment id="development"><!--事物管理器 利用jdbc控制事务 --><transactionManager type="JDBC"/><!--mybatis采用数据库链接池的方式整合数据源 --><dataSource type="POOLED"><!--高版本数据库驱动 需要添加cj--><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&amp;useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true&amp;allowMultiQueries=true"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><!--Mybatis加载Mapper映射文件--><mappers><mapper resource="mybatis/mappers/UserMapper.xml"/></mappers></configuration>

20、构建DemoUserMapper接口

/*** 说明:*1.根据面向接口开发的思想需要定义一个Mapper接口*2.在接口中可以写接口方法, 谁用谁去实现!!!*/public interface DemoUserMapper {//1.查询所有的表数据public List<DemoUser> findAll();}

21、编辑DemoUserMapper.xml配置文件

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-////DTD Mapper 3.0//EN""/dtd/mybatis-3-mapper.dtd"><!--xml映射文件 必须与接口一对一绑定namespace: 指定需要绑定的接口名称. 不能重复.--><mapper namespace="com.jt.mapper.DemoUserMapper"><!--实现接口中的方法id: 需要与接口中的方法绑定. 一般复制粘贴resultType: 对象的包路径.规则: sql语句不要添加多余的;号 Oracle数据库不能添加;号--><select id="findAll" resultType="com.jt.pojo.DemoUser">select id,name,age,sex from demo_user</select><!-- <insert id=""></insert><update id=""></update><delete id=""></delete>--></mapper>

22、编辑测试类TestMybatis,测试mybatis实现数据库查询

/*** 业务说明: 实现mybatis入门案例* 步骤:*1.动态生成SqlSessionFactory*/@Testpublic void demo1() throws IOException {//指定配置文件地址String resource = "mybatis-config.xml";//通过IO流 加载指定的配置文件InputStream inputStream = Resources.getResourceAsStream(resource);//动态生成SqlSessionFactorySqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(inputStream);//获取SqlSession 类比 数据库链接SqlSession sqlSession = sqlSessionFactory.openSession();//获取Mapper接口DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);//获取数据List<DemoUser> userList = demoUserMapper.findAll();System.out.println(userList);//关闭链接sqlSession.close();}

23、查询结果

24、编辑DemoUserMapper,根据ID查询数据

DemoUser findOne(int id);

25、编辑DemoUserMapper.xml映射文件

<!--parameterType: 参数类型mybatis中通过 #{} 获取参数resultType: 返回值结果对象--><select id="findOne" parameterType="int" resultType="com.jt.pojo.DemoUser">select * from demo_user where id = #{id}</select>

26、编辑测试类TestMybatis测试

/**** 需求: 根据ID查询数据库记录 id=1的数据*/@Testpublic void testFindOne() throws IOException {//指定配置文件地址String resource = "mybatis-config.xml";//通过IO流 加载指定的配置文件InputStream inputStream = Resources.getResourceAsStream(resource);//动态生成SqlSessionFactorySqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获取接口DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);int id = 1;DemoUser demoUser = demoUserMapper.findOne(id);System.out.println(demoUser);//关闭链接sqlSession.close();}

27、测试结果

28、@BeforeEach

该注解的作用是在执行@Test方法前调用,是测试方法提供的测试API

编辑TestMybatis2

public class TestMybatis2 {//定义公共的属性private SqlSessionFactory sqlSessionFactory;/*** mybatis的核心 SqlSessionFacotry对象* @BeforeEach: 测试API中的注解 在执行@Test注解方法时,会提前执行!!!*/@BeforeEachpublic void init() throws IOException {//1.指定资源文件String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}@Testpublic void testMybatis01(){SqlSession sqlSession = sqlSessionFactory.openSession();DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);List<DemoUser> list = demoUserMapper.findAll();System.out.println(list);sqlSession.close();}}

29、运行结果

30、根据名称查询,编辑TestMybatis2

/*** 作业:*1. 查询name="王昭君"的用户*/@Testpublic void testFindByName(){//保证每个线程都能获取一个链接SqlSession sqlSession = sqlSessionFactory.openSession();DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);String name = "王昭君";//如果不能保证结果唯一,则使用List集合接收数据.List<DemoUser> list = demoUserMapper.findByName(name);System.out.println(list);sqlSession.close();}

31、编辑DemoUserMapper.xml

<!--说明: parameterType其中的类型程序可以根据参数自动判断,所以可以省略不写根据名称,动态取值 使用#{}关键字--><select id="findByName" resultType="com.jt.pojo.DemoUser">select * from demo_user where name = #{name}</select>

32、编辑DemoUserMapper

List<DemoUser> findByName(String name);

33、运行结果

34、编辑TestMybatis2,mybatis中参数封装

/*** 需求 :2. 查询sex=女 and age > 18岁* 条件 2个*/@Testpublic void testFindBySA(){//保证每个线程都能获取一个链接SqlSession sqlSession = sqlSessionFactory.openSession();DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);//编程习惯: 面向对象DemoUser user = new DemoUser();user.setAge(18).setSex("女");List<DemoUser> list = demoUserMapper.findBySA(user);System.out.println(list);sqlSession.close();}

35、编辑DemoUserMapper

List<DemoUser> findBySA(DemoUser user);

36、编辑DemoUserMapper.xml

<!--查询sex=女 and age > 18岁参数: DemoUser user 意图:传递属性的规则: 如果传递的参数是对象,则通过#{属性} 可以直接获取数据.--><select id="findBySA" resultType="com.jt.pojo.DemoUser">select * from demo_user where sex= #{sex} and age > #{age}</select>

37、运行结果

38、编辑TestMybatis2,参数封装的3种常见情景

/*** 需求 :2. 查询sex=女 and age > 18岁* 方式1: User对象封装*/@Testpublic void testFindBySA(){//保证每个线程都能获取一个链接SqlSession sqlSession = sqlSessionFactory.openSession();DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);//编程习惯: 面向对象DemoUser user = new DemoUser();user.setAge(18).setSex("女");List<DemoUser> list = demoUserMapper.findBySA(user);System.out.println(list);sqlSession.close();}/*** sex=女 and age > 18* 方式2: @Param方式封装.*/@Testpublic void testFindBySA2(){//保证每个线程都能获取一个链接SqlSession sqlSession = sqlSessionFactory.openSession();DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);String sex = "女";int age = 18;List<DemoUser> list = demoUserMapper.findBySA2(sex,age);System.out.println(list);sqlSession.close();}/*** sex=女 and age > 18* 方式3: map集合封装*/@Testpublic void testFindBySA3(){//保证每个线程都能获取一个链接SqlSession sqlSession = sqlSessionFactory.openSession();DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);Map<String,Object> map = new HashMap<>();map.put("sex","女");map.put("age",18);List<DemoUser> list = demoUserMapper.findBySA3(map);System.out.println(list);sqlSession.close();}

39、编辑DemoUserMapper.xml

<!--查询sex=女 and age > 18岁参数: DemoUser user 意图:传递属性的规则: 如果传递的参数是对象,则通过#{属性} 可以直接获取数据.--><select id="findBySA" resultType="com.jt.pojo.DemoUser">select * from demo_user where sex= #{sex} and age > #{age}</select><!--如果参数被@Param("sex") String sex修饰则#{参数key}即可获取数据--><select id="findBySA2" resultType="com.jt.pojo.DemoUser">select * from demo_user where sex= #{sex} and age > #{age}</select><!--Map<String, Object> mapsex=女 age=18规则: 如果参数是一个map集合,则通过#{key}获取数据.--><select id="findBySA3" resultType="com.jt.pojo.DemoUser">select * from demo_user where sex= #{sex} and age > #{age}</select>

40、编辑DemoUserMapper

List<DemoUser> findBySA(DemoUser user);List<DemoUser> findBySA2(@Param("sex") String sex, @Param("age") Integer age);List<DemoUser> findBySA3(Map map);

41、编辑TestMybatis2,Mybatis常规CURD操作,新增操作

/*** 需求: 实现用户入库操作* 关于事务说明:* mybatis中的"更新"操作,默认事务都是开启的,如果进行更新操作,* 则必须提交事务.*/@Testpublic void testSaveUser(){SqlSession sqlSession = sqlSessionFactory.openSession();DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);//数据库主键自增,所以对象的ID可以为null.DemoUser user = new DemoUser(null,"宁荣荣",26,"女");int rows = demoUserMapper.saveUser(user);if(rows > 0){System.out.println("影响的行数:"+rows);//事务提交mit();}sqlSession.close();}

42、编辑DemoUserMapper

int saveUser(DemoUser user);

43、编辑DemoUserMapper.xml

<!--需求: 需要返回影响的行数.mybatis执行"更新"操作时,自动的返回影响的行数--><insert id="saveUser">insert into demo_user value (null,#{name},#{age},#{sex})</insert>

44、运行结果

45、查看数据库

46、Mybatis中的转义字符

xml文件中的转义字符.&gt; > 大于&lt; < 小于&amp; & 号说明:如果sql中有大量的转义字符 建议使用转义标签体语法: <![CDATA[ xxx内容 报文 ]]>

47、编辑TestMybatis2,查询age> 18 and age< 100 的用户信息

/*** 需求: 查询age> 18 and age< 100 的用户信息.* 规则: 如果不能使用对象封装,则一般使用Map集合*/@Testpublic void testSelect01(){SqlSession sqlSession = sqlSessionFactory.openSession();DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);Map<String,Object> map = new HashMap<>();map.put("minAge",18);map.put("maxAge",100);List<DemoUser> userList = demoUserMapper.findByAge(map);System.out.println(userList);sqlSession.close();}

48、编辑DemoUserMapper

List<DemoUser> findByAge(Map<String,Object> map);

49、编辑DemoUserMapper.xml

<select id="findByAge" resultType="com.jt.pojo.DemoUser"><!--select * from demo_user where age > #{minAge} and age &lt; #{maxAge}--><![CDATA[ select * from demo_user where age > #{minAge} and age < #{maxAge}]]></select>

50、运行结果

51、编辑TestMybatis2,Mybatis集合用法,批量删除

/*** 例如: 删除id=232/233/234的数据?* Sql: delete from demo_user where id in (232,233,234)* 规则: 如果遇到相同的多个数据,则一般采用集合的方式封装数据.* 封装方式:*1. array*2. list*3. map<List>*/@Testpublic void testDeleteIds(){SqlSession sqlSession = sqlSessionFactory.openSession(true);DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);//将数据封装为数组int[] ids = {232,233,234};demoUserMapper.deleteIds(ids);System.out.println("删除操作成功!!!");}

52、编辑DemoUserMapper

void deleteIds(int[] ids);

53、编辑DemoUserMapper.xml

<!--需求: 批量删除多个数据难点: 如果使用#{集合}获取的是集合对象的整体.删除无效.思路: 将数组拆分为单个数据. 可以通过遍历的方式操作语法: mybatis为了参数取值方便,特意封装了遍历的标签 foreach关于标签参数说明:<foreach collection=""></foreach>1.如果传递的参数是数组,则collection="array"2.如果传递的参数是list集合, 则collection="list"3.如果传递的参数是Map集合, 则collection="map中的key"标签属性说明:1.collection 集合的名称2.item 每次遍历的数据的形参变量3.open 循环的开始标签4.close 循环的结束标签5.index 循环遍历下标 一般不用6.separator 循环遍历的分割符--><delete id="deleteIds">delete from demo_user where id in (<foreach collection="array" item="id" separator=",">#{id}</foreach>)</delete>

54、编辑TestMybatis2,Mybatis集合用法,练习list/map的用法

@Testpublic void testDeleteList(){SqlSession sqlSession = sqlSessionFactory.openSession(true);DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);List list = new ArrayList();list.add(232);list.add(233);list.add(234);demoUserMapper.deleteList(list);System.out.println("删除操作成功!!!");}/** 说明: 有时业务需求导致需要使用map封装list集合*/@Testpublic void testDeleteMap(){SqlSession sqlSession = sqlSessionFactory.openSession(true);DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);List list = new ArrayList();list.add(232);list.add(233);list.add(234);HashMap map = new HashMap();map.put("ids",list);demoUserMapper.deleteMap(map);System.out.println("删除操作成功!!!");}

55、编辑DemoUserMapper

void deleteList(List list);void deleteMap(HashMap map);

56、编辑DemoUserMapper.xml

<!--删除List集合中的数据--><delete id="deleteList">delete from demo_user where id in (<foreach collection="list" item="id" separator=",">#{id}</foreach>)</delete><!--删除List集合中的数据 如何是map,则写map中的key--><delete id="deleteMap">delete from demo_user where id in (<foreach collection="ids" item="id" separator=",">#{id}</foreach>)</delete>

57、编辑TestMybatis2,模糊查询

/*Mybatis作业:需求: 查询name中包含"王"的数据.并且按照年龄降序排列*/@Testpublic void findLike(){SqlSession sqlSession = sqlSessionFactory.openSession(true);DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);String name = "%王%";List<DemoUser> list = demoUserMapper.findLike(name);System.out.println(list);sqlSession.close();}

58、编辑DemoUserMapper.xml

<!--关于模糊查询的说明: 使用%号需要使用""号包裹.注意事项: mybatis中的sql 最好小写. 因为不同的系统对于大小写 不敏感.键位: eclipse ctrl + shift + y 小写ctrl + shift + u 大写/小写--><select id="findLike" resultType="com.jt.pojo.DemoUser"><!--select * from demo_user where name like "%"#{name}"%" order by age desc -->select * from demo_user where name like #{name} order by age desc</select>

59、编辑DemoUserMapper

List<DemoUser> findLike(String name);

60、运行结果

61、编辑TestMybatis2,批量更新操作

/*** 作业2: 将name为貂蝉/黄月英/宁荣荣的年龄改为28岁,性别女*/@Testpublic void updateUser(){SqlSession sqlSession = sqlSessionFactory.openSession(true);DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);Map<String,Object> map = new HashMap<>();String[] array = {"貂蝉","黄月英","宁荣荣"};map.put("names",array);map.put("age",28);map.put("sex","女");demoUserMapper.updateUser(map);sqlSession.close();}

62、编辑DemoUserMapper.xml

<!--批量更新操作--><update id="updateUser">update demo_user set age = #{age}, sex = #{sex}where name in (<foreach collection="names" item="name" separator=",">#{name}</foreach>)</update>

63、编辑DemoUserMapper

void updateUser(Map<String,Object> map);

64、编辑mybatis-config.xml,Mybatis简化

<!--核心配置文件--><configuration><!--配置别名--><typeAliases><typeAlias type="com.jt.pojo.DemoUser" alias="DemoUser"></typeAlias></typeAliases>

65、编辑DemoUserMapper.xml,可以使用简化写法,代替类型的全路径

<mapper namespace="com.jt.mapper.DemoUserMapper"><!--实现接口中的方法id: 需要与接口中的方法绑定. 一般复制粘贴resultType: 对象的包路径.规则: sql语句不要添加多余的;号 Oracle数据库不能添加;号--><!--<select id="findAll" resultType="com.jt.pojo.DemoUser">--><select id="findAll" resultType="DemoUser">select id,name,age,sex from demo_user</select>

66、编辑mybatis-config.xml,如果有多个pojo,可以这样配置

<!--核心配置文件--><configuration><!-- 配置别名 --><typeAliases><!--别名标签只对某个类有效.--><!--<typeAlias type="com.jt.pojo.DemoUser" alias="DemoUser"></typeAlias>--><!--package 指定的是包路径的信息.--><package name="com.jt.pojo"/></typeAliases>

67、编辑DemoUserMapper.xml

<mapper namespace="com.jt.mapper.DemoUserMapper"><!--映射原理:如果配置文件中定义了包路径,则映射对象时会自动的完成路径的拼接resultType="com.jt.pojo.DemoUser"--><select id="findAll" resultType="DemoUser">select id,name,age,sex from demo_user</select>

68、编辑DemoUser,注意新增注解

@Data //动态生成get/set/toString/equals等方法@Accessors(chain = true) //开启链式加载 重写set方法@NoArgsConstructor //无参构造@AllArgsConstructor //有参构造@Alias("DemoUser")public class DemoUser implements Serializable {private Integer id;private String name;private Integer age;private String sex;}

69、Mybatis简化,sql重复,可以使用sql标签

1. select id,name,age,sex from demo_user where id = 12. select id,name,age,sex from demo_user where name = xxx

70、用法

<!--2.简化Sql标签 --><sql id="demo_user_sql">select id,name,age,sex from demo_user</sql><!--include 代表包含Sql标签 --><select id="findAll" resultType="DemoUser"><include refid="demo_user_sql"/></select>

71、sql标签的说明

优势:1.使用Sql标签可以节省xml的文件大小.2.代码的结构相对简单.弊端:1.Sql只能抽取公共的Sql语句,局限性稍大.2.如果大量的使用Sql标签,则代码的可读性差

72、编辑TestMybatis2,Mybatis,动态sql

IF-WHERE用法

/*** 封装DemoUser的对象,根据对象中不为null的属性查询*/@Testpublic void testFindWhere(){SqlSession sqlSession = sqlSessionFactory.openSession();DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);DemoUser demoUser = new DemoUser();demoUser.setAge(3000);List<DemoUser> list = demoUserMapper.findWhere(demoUser);System.out.println(list);sqlSession.close();}

73、编辑DemoUserMapper.xml

<!--动态Sql案例思路: 如果数据不为null,mybatis才会当做条件if标签说明:test: 判断的条件 直接写属性即可where标签: 去除条件中多余的 and 或者 or的说明: if和 where 几乎一起出现.--><select id="findWhere" resultType="DemoUser">select id,name,age,sex from demo_user<where><if test="name != null">name = #{name}</if><if test="age !=null"> and age=#{age}</if><if test="sex !=null"> and sex=#{sex}</if></where></select>

74、编辑DemoUserMapper

List<DemoUser> findWhere(DemoUser demoUser);

75、运行结果

76、编辑TestMybatis2,动态Sql-SET标签

/*** 需求: 根据Id,动态的实现数据的更新.*/@Testpublic void testUpdateSet(){SqlSession sqlSession = sqlSessionFactory.openSession(true);DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);DemoUser user = new DemoUser();user.setId(1).setName("守山大使");demoUserMapper.updateUser2(user);sqlSession.close();}

77、编辑DemoUserMapper

void updateUser2(DemoUser user);

78、编辑DemoUserMapper.xml

<!--规则: 根据对象中不为null的属性当做set条件set标签说明: 去除set条件中多余的 ,号--><update id="updateUser2">update demo_user<set><if test="name !=null">name = #{name},</if><if test="age !=null">age = #{age},</if><if test="sex !=null">sex = #{sex}</if></set>whereid = #{id}</update>

79、编辑TestMybatis2,动态Sql-choose when otherwise

/*** 需求: 如果存在name则按照name查询,否则按照sex查询.*/@Testpublic void testSelectChoose(){SqlSession sqlSession = sqlSessionFactory.openSession(true);DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);DemoUser user = new DemoUser();user.setSex("男");List<DemoUser> list = demoUserMapper.selectChoose(user);System.out.println(list);sqlSession.close();}

80、编辑DemoUserMapper.xml

<!--需求: 如果不想将全部的条件当做if的判断.则mybatis提供了分支结构 switch语法说明:choose:代表分支结构,只有一个条件有效.when: 指定判断的条件 和if类似.otherwise: 如果上述的条件都不满足时,该行代码有效.--><select id="selectChoose" resultType="DemoUser">select * from demo_userwhere<choose><when test="name !=null">name = #{name}</when><otherwise>sex = #{sex}</otherwise></choose></select>

81、编辑DemoUserMapper

List<DemoUser> selectChoose(DemoUser user);

82、运行结果

83、ResultMap用法

创建表dept

84、编辑Dept

@Data@Accessors(chain = true)@NoArgsConstructor@AllArgsConstructorpublic class Dept implements Serializable {//驼峰命名规则private Integer deptId;private String deptName;}

85、标签说明

resultType说明:当结果集中的字段名称,如果与属性的名称一致时,才会实现自动的数据封装resultMap说明:当结果集中的字段名称,与对象中的属性不一致时,可以使用resultMap实现自定义的封装.

86、编辑TestMybatis2,测试

@Testpublic void testFindDept(){SqlSession sqlSession = sqlSessionFactory.openSession();DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);List<Dept> list = deptMapper.findAll();System.out.println(list);sqlSession.close();}

87、编辑DeptMapper

public interface DeptMapper {List<Dept> findAll();}

88、编辑DeptMapper.xml

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-////DTD Mapper 3.0//EN""/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.jt.mapper.DeptMapper"><!--ORM思想: 对象关系映射.属性: deptId,deptName字段: dept_id,dept_nameresultType说明:当结果集中的字段名称,如果与属性的名称一致时,才会实现自动的数据封装.resultMap="" 自定义的封装数据的结构--><select id="findAll" resultMap="deptRM">select * from dept</select><!--自定义映射关系的语法:1.id标签代表主键 (每张表中都会有一个主键)1.1.column: 代表结果集中的字段.1.2.property: 对象中的属性2.result 除了主键之外的配置信息--><resultMap id="deptRM" type="Dept"><id column="dept_id" property="deptId"/><result column="dept_name" property="deptName"/></resultMap></mapper>

89、加一些数据

90、编辑mybatis-config.xml

<!--Mybatis加载Mapper映射文件--><mappers><mapper resource="mybatis/mappers/DemoUserMapper.xml"/><mapper resource="mybatis/mappers/DeptMapper.xml"/></mappers></configuration>

91、运行结果

92、编辑mybatis-config.xml,驼峰映射规则

<!--核心配置文件--><configuration><!--Mybatis的核心配置--><settings><!--开启了驼峰映射规则 dept_id 自动映射到 deptId --><setting name="mapUnderscoreToCamelCase" value="true"/></settings>

93、Mybatis中的缓存机制

引入缓存,可以有效降低用户访问物理设备的频次,提高用户响应速度

mybatis自身缓存 一级缓存/二级缓存

一级缓存:Mybatis默认开启一级缓存,一级缓存可以在同一个SqlSession对象中查询相同的数据,可以实现数据的共享

编辑TestMybatis2,测试

/*** Mybatis一级缓存: 默认开启*规则: 同一个SqlSession内部有效.*/@Testpublic void cache1(){SqlSession sqlSession = sqlSessionFactory.openSession();DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);List<DemoUser> list1 = demoUserMapper.findAll();List<DemoUser> list2 = demoUserMapper.findAll();List<DemoUser> list3 = demoUserMapper.findAll();System.out.println(list1 == list2);System.out.println(list1 == list3);System.out.println(list2 == list3);sqlSession.close();}

94、运行结果

95、二级缓存

二级缓存mybatis中默认也是开启的,但是需要手动标识

二级缓存可以在同一个SqlSessionFactory内部有效

编辑DemoUserMapper.xml,二级缓存的使用

<mapper namespace="com.jt.mapper.DemoUserMapper"><!--应用二级缓存--><cache/>

96、编辑TestMybatis2,测试

/*** 二级缓存说明:*sqlSession查询数据之后,会将缓存信息保存到一级缓存中.但是不会立即将*缓存交给二级缓存保管.如果需要使用二级缓存,则必须将sqlSession业务逻辑执行成功之后关闭.*/@Testpublic void cache2(){SqlSession sqlSession = sqlSessionFactory.openSession();DemoUserMapper demoUserMapper = sqlSession.getMapper(DemoUserMapper.class);demoUserMapper.findAll();//关闭一级缓存sqlSession.close();SqlSession sqlSession2 = sqlSessionFactory.openSession();DemoUserMapper demoUserMapper2 = sqlSession2.getMapper(DemoUserMapper.class);demoUserMapper2.findAll();sqlSession2.close();}

97、代理对象说明

JDK动态代理特点:1.要求被代理者必须实现(有)接口.2.JDK代理是jdk默认提供的.CGLIB动态代理特点:1.不管被代理者是否有接口,都可以为其创建代理对象. 代理对象是目标对象的子类.2.cglib需要手动导入jar包3.spring为了创建代理对象方便,自身自动添加cglib依赖项.

98、三大框架整合

框架概述

Spring框架:Spring为了团队开发将复杂的框架进行整合,使得程序从控制到调用浑然一体,以一种统一的方式进行调用

核心:整合第三方框架

Spring框架核心机制

IOC:控制反转: 将对象创建的权利交给Spring容器管理,由Spring容器管理对象的生命周期DI: 依赖注入创建对象时,如果该对象中有需要依赖的属性,Spring负责为属性赋值

@RestControllerpublic class UserController {@Autowiredprivate UserService userService;}

AOP 面向切面编程

99、SpringMVC

该框架的主要的作用,接收用户的请求,之后完成业务处理,最终返回响应给用户

创建项目:模型,springboot项目

100、选择版本信息

101、pom.xml文件

<?xml version="1.0" encoding="UTF-8"?><project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.6</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.jt</groupId><artifactId>springboot_ssm</artifactId><version>0.0.1-SNAPSHOT</version><name>springboot_ssm</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.5.6</spring-boot.version></properties><dependencies><!--springBoot整合mvc--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--springBoot整合测试方法--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--支持热部署 开发阶段有效--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><!--引入插件lombok 自动的set/get/构造方法插件 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--mybatis依赖包--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version></dependency><!--jdbc依赖包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.4.1</version><configuration><mainClass>com.jt.SpringbootDemo1Application</mainClass></configuration><!--排除一些指定的配置--><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>

102、编辑User

@Data@Accessors(chain = true)@NoArgsConstructor@AllArgsConstructorpublic class User implements Serializable {private Integer id;private String name;private Integer age;private String sex;}

103、编辑UserMapper

public interface UserMapper {//查询demo_user表中的所有数据List<User> findAll();}

104、编辑UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-////DTD Mapper 3.0//EN""/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.jt.mapper.UserMapper"><select id="findAll" resultType="com.jt.pojo.User">select * from demo_user</select></mapper>

105、编辑UserService接口及其实现类

public interface UserService {//查询user表中的所有的数据List<User> findAll();}

@Service //将该类交给Spring容器管理public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper; //代理对象 JDK动态代理@Overridepublic List<User> findAll() {//List<User> userList = userMapper.findAll();//return userList;return userMapper.findAll();}}

106、编辑UserController

@RestController //@Controller 将该类交给Spring容器管理 +//@ResponseBody 业务返回值时,将数据转化为JSON.public class UserController {@Autowiredprivate UserService userService;/*** 需求: 查询全部user表数据* 请求类型: get/post/put/delete* 路径: /findUser* 参数: 无* 返回值: List<User>*/@RequestMapping("/getUser")public List<User> findUser(){return userService.findAll();}}

107、编辑核心配置application.yml,数据源配置

1. serverTimezone=GMT%2B8 指定时区 东八区2. useUnicode=true&characterEncoding=utf8开启使用Unicode编码,并且指定字符集utf-83. autoReconnect=true 断线是否重新链接.4. &allowMultiQueries=true 是否允许批量操作

#语法: 1.key:(空格)value结构server:port: 8090#整合数据源spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=trueusername: rootpassword: root#SpringBoot整合mybatismybatis:#指定别名包type-aliases-package: com.jt.pojo#加载指定的xml映射文件mapper-locations: classpath:/mybatis/mappers/*.xml#开启驼峰映射configuration:map-underscore-to-camel-case: true

108、启动一下项目,报错

109、解决问题的两种方式,UserMapper接口和启动类

@Mapper //将该接口交给Spring容器管理public interface UserMapper {//查询demo_user表中的所有数据List<User> findAll();}

@SpringBootApplication@MapperScan("com.jt.mapper") //根据包扫描路径,扫描全部的mapper接口文件public class SpringbootSsmApplication {public static void main(String[] args) {SpringApplication.run(SpringbootSsmApplication.class, args);}}

110、访问:localhost:8090/getUser,浏览器页面显示

111、RestFul实现参数传递

根据ID查询数据

Get请求类型

url:http://localhost:8090/findUserById?id=1

编辑UserController

/*** 业务: 根据ID查询用户数据.* 请求类型: get* URL:http://localhost:8090/findUserById?id=1* 参数: id=1* 返回值: User对象* SpringMVC业务规范:*1.接收参数时,必须与用户参数保持一致.*///@RequestMapping(value = "findUserById",method = RequestMethod.GET)@GetMapping("findUserById") //只能接收Get请求类型public User findUserById(Integer id){return userService.findUserById(id);}

112、编辑UserService接口及其实现类

User findUserById(Integer id);

@Overridepublic User findUserById(Integer id) {return userMapper.findUserById(id);}

113、编辑UserMapper接口和UserMapper.xml映射文件

User findUserById(Integer id);

<select id="findUserById" resultType="User">select * from demo_user where id = #{id}</select>

114、访问:localhost:8090/findUserById?id=6,浏览器页面显示

115、什么是Servlet

Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。

狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

概括: Servlet是java后台程序与用户交互的机制(媒介)

编辑UserController

//http://localhost:8090/findUserByIds?id=1,3,5,6,7@GetMapping("/findUserByIds")public String findUserByIds(HttpServletRequest request){String id = request.getParameter("id");//id串String[] idStr = id.split(",");//数字数组Integer[] intArray = new Integer[idStr.length];//多少个数字长度的Integer类型的新空数组for (int i=0; i<idStr.length; i++){intArray[i] = Integer.parseInt(idStr[i]);//对应位置赋值System.out.println(intArray[i]);}return "参数接收成功!!!";}

116、访问:localhost:8090/findUserByIds?id=1,3,5,7,9,11,页面和控制台分别显示

117、编辑application.yml,Sql日志输出

#Sql日志文件打印logging:level:com.jt.mapper: debug

118、编辑UserController,SpringMVC参数传值说明,简单参数传值

/*** URL:http://localhost:8090/mvc?name="李四"* @return*/@GetMapping("/mvc")public Object testDemo(String name){return "参数名称:"+name;}

119、访问:localhost:8090/mvc?name="李四",浏览器页面显示

120、编辑UserController,使用对象接收数据

如果用户传递的数据有多个,则可以使用对象接收

/*** URL:http://localhost:8090/mvc2?name="李四"&age=18&sex="女"* 说明: 如果使用对象的方式进行接收,则必须有Setxx方法.* @return*/@GetMapping("/mvc2")public Object testDemo(User user){return "参数名称:"+user;}

121、访问:localhost:8090/mvc2?name="牛魔王"&age=44&sex="男",浏览器页面显示

122、编辑UserController,restful业务说明

/*** 更新操作 利用restFul的结构, 根据Id修改数据,修改name/age* URL:http://localhost:8090/user/貂蝉/18/227 PUT* 查询: http://localhost:8090/user/18 GET* 解析: URL:http://localhost:8090/user/{name}/{age}/{id}** RestFul语法:*1.用户url编辑*1.1 参数与参数之间使用/分割.*1.2 restFul结构顺序一旦确定,不能随意更改*1.3 如果使用restFul结构,请求路径中不能出现动词.隐藏目的.**2.用户规范:*由于restFul结构请求路径都是名词,所以不能区分业务逻辑.*所以采用请求类型,严格区分业务需求.*2.1 GET 查询操作*2.2 POST 新增操作/form表单提交*2.3 PUT 修改操作*2.4 DELETE 删除操作**3.参数接收*1.参数与参数之间使用/分割.*2.参数必须使用{xxx}包裹*3.使用特定的注解@PathVariable("name") String name 接收参数*4.如果接收参数的名称与对象中的属性名称一致,则可以使用对象接收*/@GetMapping("/user/{name}/{age}/{id}")public Object restFul(User user){userService.update(user);return "数据更新成功!!!";}

123、编辑UserService及其实现类

void update(User user);

@Overridepublic void update(User user) {userMapper.update(user);}

124、编辑UserMapper

//@Delete("xxxxx")//@Insert("sql语句")//@Select("查询操作的sql")@Update("update demo_user set name=#{name}, age=#{age} where id=#{id}")void update(User user);

125、访问:localhost:8090/user/戴沐白/37/23,页面和数据库分别显示

126、前后端调用,vue入门案例

<!DOCTYPE html><html><head><meta charset="utf-8"><title>hello 入门案例</title></head><body><div id="app"><h1>双向数据绑定测试</h1><!-- {{插值表达式}} --><h3>获取数据:{{ msg }}</h3></div><!-- 使用步骤:1.导入js.文件2.准备根标签3.创建vue对象,并且实现挂载.4.定义属性.实现数据动态取值知识补充: new Vue({}) 函数式编程关于变量说明:1. js中变量定义 早期 var 全局变量 没有作用域.2. let有作用域的概念3. const 常量定义 不允许修改--><!-- 引入js --><script src="../js/vue.js"></script><script type="text/javascript">const app = new Vue({//element 元素el: "#app",data: {msg: "您好 Vue JS"}})</script></body></html>

127、HBuilderX上显示

128、点击运行,运行到浏览器,Chrome,浏览器上显示

129、VUE生命周期函数

概念: 生命周期函数,是VUE针对与用户提供的扩展的功能.如果编辑了生命周期函数,则vue对象自动执行,无需手动调用.生命周期函数种类:1. 初始化阶段 beforeCreate created beforeMount mounted VUE对象正在的实例化2. Vue对象的修改 beforeUpdate, updated3. 对象销毁 beforeDestroy destroyed

130、案例

<!DOCTYPE html><html><head><meta charset="utf-8"><title>测试vue生命周期函数</title></head><body><div id="app"><h3 v-text="msg"></h3><button @click="update">更新</button><button @click="destroy">销毁</button></div><!--引入js函数类库 --><script src="../js/vue.js"></script><script>const app = new Vue({el : "#app",data : {msg: "vue生命周期"},//在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。beforeCreate(){console.log("beforeCreate")},//在实例创建完成后被立即调用created(){console.log("created")},//在挂载开始之前被调用:相关的 render 函数首次被调用。beforeMount(){console.log("beforeMount")},//实例被挂载后调用,这时 el 被新创建的 vm.$el 替换了。mounted(){console.log("mounted")},//数据更新时调用,发生在虚拟 DOM 打补丁之前beforeUpdate(){console.log("beforeUpdate")},//由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。updated(){console.log("updated")},//实例销毁之前调用。在这一步,实例仍然完全可用beforeDestroy(){console.log("beforeDestroy")},//实例销毁后调用。destroyed(){console.log("destroyed")},methods:{destroy(){this.$destroy()},update(){this.msg="vue"}}})</script></body></html>

131、运行至浏览器,打开开发者工具,清除刷新,点击页面按钮,页面和开发者工具上分别显示

132、前后端调用Axios,Ajax

同步:一个线程依次加载执行,如果数据没有加载完成,则其他数据处于等待的状态

异步:Ajax特点:局部刷新,异步访问 Ajax为什么可以异步:Ajax的设计原理-Ajax引擎

Ajax引擎

用户发起请求,交给Ajax引擎进行处理, 用户可以执行其它的操作.Ajax引擎接收到用户请求之后, 发起Http请求访问目标服务器.后台服务器将数据返回给Ajax引擎.Ajax引擎 将最终获取的数据 通过回调函数的方式 交给用户处理.

133、Axios案例练习

134、启动后台,运行页面,打开开发者工具,刷新,出现错误

135、解决跨域问题

136、开发者工具页面显示

137、根据id查询数据

/* 带参数的数据传递 通过?号传递数据*/let url1 = "http://localhost:8090/axios/findUserById?id=8"axios.get(url1).then(function(result){console.log(result.data)})

138、编辑AxiosController

@RestController@CrossOrigin@RequestMapping("/axios")public class AxiosController {@Autowiredprivate UserService userService;/*** 根据ID查询用户信息* URL: http://localhost:8090/axios/findUserById?id=1*/@GetMapping("/findUserById")public User findUserById(Integer id){return userService.findUserById(id);}

139、重启后台,刷新页面,开发者工具页面显示

140、根据name和age查询数据

/*** 作业2: 根据age/sex查询用户信息* url地址: http://localhost:8090/axios/findUserByAS* 参数: id=1* 返回值: console.log输出 * 知识点: 根据对象传递参数时,使用params关键字*/let url2 = "http://localhost:8090/axios/findUserByAS"//封装对象let user = {age: 18,sex: "女"}axios.get(url2,{params : user}).then(function(promise){console.log(promise.data)})

141、编辑AxiosController

/*** 根据age和sex查询数据* URL地址:http://localhost:8090/axios/findUserByAS?age=18&sex=%E5%A5%B3* 请求类型: get* 参数: age/sex* 返回值: list<User>*/@GetMapping("/findUserByAS")public List<User> findUserByAS(User user){return userService.findUserByAS(user);}

142、编辑UserService及其实现类

List<User> findUserByAS(User user);

@Overridepublic List<User> findUserByAS(User user) {return userMapper.findUserByAS(user);}

143、编辑UserMapper

@Select("select * from demo_user where age=#{age} and sex=#{sex}")List<User> findUserByAS(User user);

144、开发者工具页面显示

145、Axios-GET-RestFul

/* 案例三: 利用restFul实现数据获取需求: 根据name/sex查询数据模板字符串: 语法ES7的写法 一对反引号进行数据拼接,通过${} 获取变量*/ let name = "宁荣荣"let sex = "女"//let url3 = "http://localhost:8090/axios/user/"+name+"/"+sexlet url3 = `http://localhost:8090/axios/user/${name}/${sex}`axios.get(url3).then(function(promise){console.log(promise.data)})

146、编辑AxiosController

/*** 业务说明: 接收restFul请求* URL:http://localhost:8090/axios/user/${name}/${sex}* 参数: name/sex* 结果: List<User>*/@GetMapping("/user/{name}/{sex}")public List<User> findUserByNS(User user){return userService.findUserByNS(user);}

147、编辑UserService及其实现类

List<User> findUserByNS(User user);

@Overridepublic List<User> findUserByNS(User user) {return userMapper.findUserByNS(user);}

148、编辑UserMapper

@Select("select * from demo_user where name=#{name} and sex=#{sex}")List<User> findUserByNS(User user);

149、开发者工具页面显示

150、Axios-POST/PUT,编辑JS

/*** 业务: 实现post请求入库操作 实现入库用户* 知识点: * 1.post请求中的参数 axios.post(url,user)*/let url = "http://localhost:8090/axios/saveUser"let user2 = {name: "石昊",age: 25,sex: "男"}axios.post(url,user2).then(function(promise){console.log(promise.data)})

151、编辑AxiosController

/*** 业务:实现用户的新增* URL: http://localhost:8090/axios/saveUser* 参数: {"name":"石昊","age":25,"sex":"男"} JSON串* 返回值: String 新增成功* 知识点: post请求传递对象时,传递的数据是一个json串.不能直接为User对象赋值.* 解决方案:* 1.对象转化为JSON @ResponseBody* 2.JSON转化为对象 @RequestBody*/@PostMapping("/saveUser")public String saveUser(@RequestBody User user){System.out.println(user);userService.saveUser(user);return "用户入库成功!!!";}

152、编辑UserService及其实现类,编辑UserMapper

void saveUser(User user);

@Overridepublic void saveUser(User user) {userMapper.saveUser(user);}

@Insert("insert into demo_user value(null,#{name},#{age},#{sex})")void saveUser(User user);

153、重启后台,打开开发者工具页面,清除,刷新,显示

154、查询一下数据库

155、Axios简化操作

let user2 = {name: "火灵儿",age: 24,sex: "女"} //指定公共的请求前缀axios.defaults.baseURL = "http://localhost:8090"axios.post("/axios/saveUser",user2).then(function(promise){console.log(promise.data)})

156、可以新增成功

157、async-await关键字

//1.指定请求前缀axios.defaults.baseURL = "http://localhost:8090"/*** 需求: 要求ajax请求在一行完成!* 解决方案: async-await* 语法说明:* 1.async 必须标识函数方法* 2.await 必须标识ajax请求* 实际意义:* 解决了ajax中的头号难题, "回调地狱"问题*///1.定义函数async function getUser(){let promise = await axios.get("/getUser")console.log(promise.data)//解构赋值 固定写法 死记硬背let {data: result} = await axios.get("/getUser")console.log(result)}//2.调用函数getUser()

158、开发者工具页面显示

159、前后端项目调用案例

用户列表展现

用户只要一访问页面,就要发起Ajax请求,访问后端服务器获取用户列表数据

编辑页面

<!DOCTYPE html><html><head><meta charset="utf-8"><title>用户列表展现案例</title></head><body><div id="app"><div align="center"><h3 align="center">用户新增</h3><br><p>用户名称: <input type="text" name="name"/>用户年龄: <input type="text" name="age"/>用户性别: <input type="text" name="sex"/><button>新增</button></p></div><hr /><div align="center"><h3 align="center">用户修改操作</h3><br><p>用户ID号: <input type="text" name="id" disabled/>用户名称: <input type="text" name="name"/>用户年龄: <input type="text" name="age"/>用户性别: <input type="text" name="sex"/><button>修改</button></p></div><h1 align="center">用户列表展现案例</h1><table align="center" border="1px" width="80%"><tr align="center"><td>ID编号</td><td>姓名</td><td>年龄</td><td>性别</td><td>操作</td></tr><tr align="center" v-for="user in userList"><td v-text="user.id"></td><td v-text="user.name"></td><td v-text="user.age"></td><td v-text="user.sex"></td><td><button>修改</button><button>删除</button></td></tr></table></div><script src="../js/axios.js"></script><script src="../js/vue.js"></script><script>//为axios执行前缀axios.defaults.baseURL="http://localhost:8090"const app = new Vue({el: "#app",data: {//3.定义数据列表userList: []},methods: {//2.定义获取列表数据的函数async getUserList(){let {data: result} = await axios.get("/axios/findAll")//console.log(result)//将ajax返回值传递给Vuethis.userList = result}},mounted(){//1利用生命周期函数调用getUser函数this.getUserList()}})</script></body></html>

160、运行至浏览器,显示

161、编辑AxiosController

/*** 需求:获取user全部列表* URL: /axios/findAll* 参数: 没有* 返回值: List<User>*/@GetMapping("/findAll")public List<User> findAll(){return userService.findAll();}

162、重启,刷新一下页面,显示

163、用户新增,编辑页面

<div align="center"><h3 align="center">用户新增</h3><br><p><!-- 用户名称: <input type="text" name="name"/>用户年龄: <input type="text" name="age"/>用户性别: <input type="text" name="sex"/><button>新增</button> --><!-- 看到input框架 第一时间想到双向数据绑定 -->用户名称: <input type="text" name="name" v-model="addUser.name"/>用户年龄: <input type="text" name="age" v-model="addUser.age" />用户性别: <input type="text" name="sex" v-model="addUser.sex" /><button @click="addUserBtn">新增</button></p></div>

164、JS封装属性

const app = new Vue({el: "#app",data: {//3.定义数据列表userList: [],//指定新增对象addUser: {name: '',age: '',sex: ''}},

165、JS方法实现

},async addUserBtn(){//将数据实现入库操作let {data: result} = await axios.post("axios/saveUser", this.addUser)//用户提示alert(result)//清空原有数据this.addUser = {}//如果新增成功,应该重新获取列表信息this.getUserList()}},

166、在页面操作,可以新增成功

167、用户修改,数据回显

168、定义更新对象

169、实现数据回显

170、添加修改点击事件

<div align="center"><h3 align="center">用户修改操作</h3><br><p><!-- 用户ID号: <input type="text" name="id" disabled/>用户名称: <input type="text" name="name"/>用户年龄: <input type="text" name="age"/>用户性别: <input type="text" name="sex"/><button>修改</button> -->用户ID号: <input type="text" name="id"v-model="updateUser.id" disabled/>用户名称: <input type="text" name="name" v-model="updateUser.name"/>用户年龄: <input type="text" name="age" v-model="updateUser.age" />用户性别: <input type="text" name="sex" v-model="updateUser.sex" /><button @click="updateUserCommit">修改</button></p></div>

171、修改函数

172、编辑AxiosController

/*** 业务: 实现用户更新* URL: /axios/updateUser* 参数: json串* 返回值: 提示信息*/@PutMapping("updateUser")public String updateUser(@RequestBody User user){userService.updateUser(user);return "更新操作成功!";}

173、编辑UserService及其实现类,编辑UserMapper

void updateUser(User user);

@Overridepublic void updateUser(User user) {userMapper.updateUser(user);}

@Update("update demo_user set name=#{name},age=#{age},sex=#{sex} where id=#{id}")void updateUser(User user);

174、用户删除

<tr align="center" v-for="user in userList"><td v-text="user.id"></td><td v-text="user.name"></td><td v-text="user.age"></td><td v-text="user.sex"></td><td><button @click="updateBtn(user)">修改</button><button @click="deleteBtn(user)">删除</button></td></tr>

175、删除函数

176、编辑AxiosController

/*** 业务:实现用户删除* URL:axios/deleteUser'+id* 参数:id* 返回值:提示信息*/@DeleteMapping("/deleteUser/{id}")public String deleteUser(@PathVariable Integer id){userService.deleteUserById(id);return "删除操作成功!";}

177、编辑UserService及其实现类,编辑UserMapper

void deleteUserById(Integer id);

@Overridepublic void deleteUserById(Integer id) {userMapper.deleteUserById(id);}

@Delete("delete from demo_user where id=#{id}")void deleteUserById(Integer id);

178、京淘项目前端项目搭建,node.js安装

179、导入前端项目后的效果

180、后端项目搭建,模板,springboot项目

181、编辑pom.xml文件

<?xml version="1.0" encoding="UTF-8"?><project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.6</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.jt</groupId><artifactId>jt</artifactId><version>0.0.1-SNAPSHOT</version><name>jt</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.5.6</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.4.1</version><configuration><mainClass>com.jt.SpringbootDemo1Application</mainClass></configuration><!--排除一些指定的配置--><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>

182、将ssm的src文件导入jt

183、编辑application.yml,修改后端端口号

184、项目环境结构

185、项目测试,访问:localhost:8091/findAll,浏览器显示

186、首页跳转说明

当用户访问localhost:8080时,开始访问系统首页

根据路由规则实现跳转,当用户访问/时,重定向发起新请求/login

根据“/login”的请求,跳转到登录组件

187、关于axios引入说明

在核心main.js中引入axios

定义axios请求访问前缀

实现父子组件参数传递

子组件引用axios,通过this.$http引用axios

188、完成用户登录,编辑SysResult对象

@Data@Accessors(chain = true)@NoArgsConstructor@AllArgsConstructorpublic class SysResult {private Integer status; //200正常 201失败private String msg;//服务器返回提示信息private Object data; //服务器返回业务数据/*** 说明: SysResult对象是系统的返回值对象,调用的次数较多.* 如果每次都需要手动添加200/201 则较为繁琐,能否封装一些方法* 简化代码调用????* 解决方案: 添加静态方法简化调用!!!*/public static SysResult fail(){return new SysResult(201,"服务器调用失败!",null);}public static SysResult success(){return new SysResult(200,"服务器调用成功!",null);}//重载规则:参数不要耦合,否则会产生歧义.public static SysResult success(Object data){return new SysResult(200,"服务器调用成功!",data);}public static SysResult success(String msg,Object data){return new SysResult(200,msg,data);}}

189、实现用户登录,编辑UserController

/*** 需求: 根据u/p查询数据库,返回秘钥token* URL: /user/login* 类型: post* 参数: username/password json* 返回值: SysResult对象(token)*/@PostMapping("/login")public SysResult login(@RequestBody User user){String token = userService.findUserByUP(user);if(token == null || "".equals(token)){//表示用户名和密码错误return SysResult.fail();}//表示用户名和密码正确,返回秘钥信息return SysResult.success(token);}

190、编辑UserService及其实现类

String findUserByUP(User user);

//根据username/password查询数据库@Overridepublic String findUserByUP(User user) {//1.将密码加密byte[] bytes = user.getPassword().getBytes();String md5Pass = DigestUtils.md5DigestAsHex(bytes);user.setPassword(md5Pass);//2.根据用户名和密文查询数据库User userDB = userMapper.findUserByUP(user);//3.判断userDB是否有值if(userDB == null){//查询没有数据.返回nullreturn null;}String token = "秘钥";return token;}

191、编辑UserMapper

@Select("select * from user where username=#{username} and password=#{password}")User findUserByUP(User user);

192、编辑UserServiceImpl

//根据username/password查询数据库@Overridepublic String findUserByUP(User user) {//1.将密码加密byte[] bytes = user.getPassword().getBytes();String md5Pass = DigestUtils.md5DigestAsHex(bytes);user.setPassword(md5Pass);//2.根据用户名和密文查询数据库User userDB = userMapper.findUserByUP(user);//3.判断userDB是否有值if(userDB == null){//查询没有数据.返回nullreturn null;}//秘钥特点: 唯一性,迷惑性 UUID:几乎可以保证唯一性return UUID.randomUUID().toString().replace("-","");}

193、登录的前端JS的说明

login () {// 获取表单对象之后进行数据校验// valid 表示校验的结果 true表示通过 false表示失败this.$refs.loginFormRef.validate(async valid => {// 如果没有完成校验则直接返回if (!valid) return// 如果校验成功,则发起ajax请求const { data: result } = await this.$http.post('/user/login', this.loginForm)if (result.status !== 200) return this.$message.error('用户登录失败')this.$message.success('用户登陆成功')// 获取用户token信息const token = result.datawindow.sessionStorage.setItem('token', token)// 用户登录成功之后,跳转到home页面this.$router.push('/home')})}

194、Session和Cookie选择

特点:1.如果数据需要临时保存,则选用Session, 如果数据需要长时间存储选用Cookie.2.如果对于安全性要求较高的数据,选用Session,如果安全性要求不高选用Cookie.问题: 财务系统用户信息选用什么技术保存信息? 选用session.

195、实现系统首页跳转

用户完成登录之后,系统应该跳转到系统首页,用户请求如下

localhost:8080/#/home

编辑路由实现系统首页跳转,index.js

196、登录之后,页面效果

197、VUE的路由导航守卫

用户在未经登录的条件下,可以直接访问其他页面,导致系统不安全。如果需要控制该漏洞,则需要在前端进行权限的校验。校验的规则:如果用户访问没有token信息,则表示用户没有登录,则需要跳转到登录页面难点:如何实现每一次的请求都要校验解决方案:拦截器

198、路由导航守卫(拦截器),编辑index.js

// 定义路由导航守卫 考点: 拦截器/*** 1.遍历的每个路由都会执行回调函数.* 2.参数信息: 3个* 2.1 to: 请求访问的地址 到哪去* 2.2 from: 请求从哪里跳转而来从哪来* 2.3 next: 是一个函数 next() 请求放行*next("/login") 发起login请求*/router.beforeEach((to, from, next) => {if(to.path === '/login'){//1.直接跳转并且结束代码return next()}// 2.不是访问的登录页面,所以判断用户是否登录. 判断依据tokenlet token = window.sessionStorage.getItem('token')if(token !== null && token !==''){ //更加安全//有值,跳转指定页面return next()}//3.如果数据为空则跳转到登录页面next('/login')})export default router

199、左侧菜单列表实现,权限层级代码结构

200、前端页面JS分析,生命周期函数,触发ajax请求

201、获取远程服务器数据

202、菜单列表实现,编辑RightsController

@RestController@CrossOrigin@RequestMapping("/rights")public class RightsController {@Autowiredprivate RightsService rightsService;/*** 业务说明: 完成菜单列表查询 1-2级* URL: /rights/getRightsList* 请求方式: get请求* 参数: 没有参数* 返回值: SysResult(List)*/@GetMapping("getRightsList")public SysResult getRightsList(){List<Rights> list = rightsService.getRightsList();return SysResult.success(list);}}

203、编辑Rights

@Data@Accessors(chain = true)public class Rights implements Serializable {private Integer id;private String name;private Integer parentId;private String path;private Integer level;private Date created;private Date updated;private List<Rights> children;}

204、编辑RightsService及其实现类

public interface RightsService {List<Rights> getRightsList();}

@Servicepublic class RightsServiceImpl implements RightsService {@Autowiredprivate RightsMapper rightsMapper;@Overridepublic List<Rights> getRightsList() {return rightsMapper.getRightsList();}}

205、编辑RightsMapper

public interface RightsMapper {List<Rights> getRightsList();}

206、编辑RightsMapper.xml

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-////DTD Mapper 3.0//EN""/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.jt.mapper.RightsMapper"><select id="getRightsList" resultMap="rightsRM">SELECT p.id,p.name,p.parent_id,p.path,p.level,p.created,p.updated,c.id c_id,c.name c_name,c.parent_id c_parent_id,c.path c_path,c.level c_level,c.created c_created,c.updated c_updated FROM(SELECT * FROM rights WHERE parent_id = 0) pLEFT JOINrights cONp.id = c.parent_id</select><!--完成左侧菜单列表的数据封装 1-2级--><resultMap id="rightsRM" type="Rights" autoMapping="true"><id property="id" column="id"></id><!--封装一对多数据--><collection property="children" ofType="Rights" javaType="java.util.List"><id property="id" column="c_id"/><result property="name" column="c_name"/><result property="parentId" column="c_parent_id"/><result property="path" column="c_path"/><result property="level" column="c_level"/><result property="created" column="c_created"/><result property="updated" column="c_updated"/></collection></resultMap></mapper>

207、启动后台服务器,登录系统,浏览器页面显示

208、利用mybatis子查询的方式获取数据(扩展),编辑RightsMapper

public interface RightsMapper {List<Rights> getRightsList();List<Rights> getRightsList2();}

209、编辑RightsMapper.xml

<!--利用子查询的方式获取数据弊端: 查询的效率低--><select id="getRightsList2" resultMap="childrenRM">select * from rights where parent_id=0</select><resultMap id="childrenRM" type="Rights" autoMapping="true"><id property="id" column="id"></id><!--一对多封装 column="子查询的条件中传递的参数"--><collection property="children" ofType="Rights"select="selectRightsByParentId" column="id"/></resultMap><!--单表查询子结果--><select id="selectRightsByParentId" resultType="Rights">SELECT * FROM rights WHERE parent_id=#{id}</select>

210、用户模块实现,实现子级路由跳转

路由填充位设定,在Home.vue中定义路由占位符

211、实现父子关系的路由映射,通过children属性实现父子组件跳转功能

212、页面效果

213、用户列表展现,页面JS分析,生命周期函数,user.vue

214、获取列表页面的JS

215、编辑分页对象PageResult

@Data@Accessors(chain = true)@NoArgsConstructor@AllArgsConstructorpublic class PageResult {private String query; //查询数据private Integer pageNum; //页数private Integer pageSize; //条数private Long total; //总数private Object rows; //查询的结果}

216、编辑UserController

/*** 需求: 利用分页查询用户信息* URL: /user/list* 参数: http://localhost:8091/user/list?query=查询关键字&pageNum=1&pageSize=10* 返回值: SysResult(pageResult)*/@GetMapping("/list")public SysResult getUserListByPage(PageResult pageResult){pageResult = userService.getUserListByPage(pageResult);return SysResult.success(pageResult);}

217、编辑UserService及其实现类

public interface UserService {List<User> findAll();String findUserByUP(User user);PageResult getUserListByPage(PageResult pageResult);}

/*** 分页Sql: 每页10条*select * from user limit 起始位置,查询条数* 第一页:*select * from user limit 0,10 0-9 含头不含尾* 第二页:*select * from user limit 10,10* 第三页:*select * from user limit 20,10* 第N页:*select * from user limit (页数-1)条数,条数* @param pageResult* @return*/@Overridepublic PageResult getUserListByPage(PageResult pageResult) {//1.总数long total = userMapper.findTotal();//2.分页结果int size = pageResult.getPageSize(); //条数int start = (pageResult.getPageNum()-1) * size; //起始位置String query = pageResult.getQuery(); //查询条件//查询分页数据List<User> userList = userMapper.findUserListByPage(start,size,query);//将返回值结果进行封装return pageResult.setTotal(total).setRows(userList);}

218、编辑UserMapper

public interface UserMapper {//查询demo_user表中的所有数据List<User> findAll();@Select("select * from user where username=#{username} and password=#{password}")User findUserByUP(User user);@Select("select count(1) from user")long findTotal();List<User> findUserListByPage(@Param("start") int start,@Param("size") int size,@Param("query") String query);}

219、编辑UserMapper.xml

<!--需求:query有参数 则添加like关键字如果数据不等于null并且同时不等于''串时,条件生效 &&--><select id="findUserListByPage" resultType="User">SELECT * FROM USER<where><!--<if test="query !=null &amp;&amp; query !=''" >username LIKE "%"#{query}"%"</if>--><if test="query !=null and query !=''" >username LIKE "%"#{query}"%"</if></where>LIMIT #{start},#{size}</select>

220、页面效果

221、用户状态修改,当点击开关,则实现状态信息的修改,status=true/false

222、请求路径,开发者工具

223、页面JS分析

224、添加修改事件

225、编辑UserController

/*** 需求: 根据Id修改状态* URL: /user/status/{id}/{status} restFul* 参数: id/status* 请求方式: put* 返回值: SysResult对象*/@PutMapping("/status/{id}/{status}")public SysResult updateStatusById(User user){userService.updateStatusById(user);return SysResult.success();}

226、编辑UserService及其实现类

public interface UserService {List<User> findAll();String findUserByUP(User user);PageResult getUserListByPage(PageResult pageResult);void updateStatusById(User user);}

@Overridepublic void updateStatusById(User user) {userMapper.updateStatusById(user);}

227、编辑UserMapper

@Update("update user set status = #{status} where id = #{id}")void updateStatusById(User user);

228、用户新增,页面弹出框效果

<!-- 编辑用户新增对话框 visible.sync 控制对话框的显示--><el-dialog title="添加用户" :visible.sync="dialogVisible" width="50%" @close="closeDialog"><!-- 定义用户提交表单数据--><el-form :model="addUserModel" :rules="rules" ref="addUserRef" label-width="100px" class="demo-ruleForm"><el-form-item label="用户名" prop="username"><el-input v-model="addUserModel.username"></el-input></el-form-item><el-form-item label="密码" prop="password"><el-input v-model="addUserModel.password" type="password"></el-input></el-form-item><el-form-item label="密码确认" prop="password2"><el-input v-model="addUserModel.password2" type="password"></el-input></el-form-item><el-form-item label="电话" prop="phone"><el-input v-model="addUserModel.phone"></el-input></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="addUserModel.email"></el-input></el-form-item></el-form><span slot="footer" class="dialog-footer"><el-button @click="dialogVisible = false">取 消</el-button><el-button type="primary" @click="addUserBtn">确 定</el-button></span></el-dialog>

229、页面JS分析,点击确定事件

230、函数说明

231、编辑UserController

/*** 用户新增* URL: /user/addUser* 请求方式: post* 参数: JS对象经过浏览器解析变为JSON串* {"username":"111","password":"222","password2":"222","email":"22@","phone":"13111111111"}* 返回值: SysResult对象*对象转化为JSON @ResponseBody*JSON转化为对象 @RequestBody 规则*/@PostMapping("/addUser")public SysResult saveUser(@RequestBody User user){userService.saveUser(user);return SysResult.success();}

232、编辑UserService及其实现类

public interface UserService {List<User> findAll();String findUserByUP(User user);PageResult getUserListByPage(PageResult pageResult);void updateStatusById(User user);void saveUser(User user);}

/*** 业务:实现业务数据封装* 1.密码加密* 2.设定默认状态* 3.设定默认时间*/@Overridepublic void saveUser(User user) {String password = user.getPassword();String MD5Pass = DigestUtils.md5DigestAsHex(password.getBytes());//获取当前时间Date date = new Date();user.setPassword(MD5Pass).setStatus(true).setCreated(date).setUpdated(date);userMapper.saveUser(user);}

233、编辑UserMapper

public interface UserMapper {//查询demo_user表中的所有数据List<User> findAll();@Select("select * from user where username=#{username} and password=#{password}")User findUserByUP(User user);@Select("select count(1) from user")long findTotal();List<User> findUserListByPage(@Param("start") int start,@Param("size") int size,@Param("query") String query);@Update("update user set status = #{status} where id = #{id}")void updateStatusById(User user);void saveUser(User user);}

234、编辑UserMapper.xml

<!--实现user入库操作--><insert id="saveUser">insert into user value (null,#{username},#{password},#{phone},#{email},#{status},#{created},#{updated})</insert>

235、用户修改数据回显,页面JS

236、根据id获取数据

237、页面JS函数

238、编辑UserController

/*** 业务分析:根据用户ID查询数据库* URL地址:"/user/"+user.id* 请求方式:get* 返回值:SysResult对象*/@GetMapping("/{id}")public SysResult findUserById(@PathVariable Integer id){User user = userService.findUserById(id);return SysResult.success(user);}

239、编辑UserService及其实现类

User findUserById(Integer id);

@Overridepublic User findUserById(Integer id) {return userMapper.findUserById(id);}

240、编辑UserMapper

@Select("select * from user where id=#{id}")User findUserById(Integer id);

241、页面效果

242、用户修改操作,页面JS分析,修改按钮说明

243、 编辑页面JS

244、编辑UserController

/*** 用户修改操作* URL: /user/updateUser* 参数: User(id/phone/email) JSON串* 请求方式: put* 返回值: SysResult对象*/@PutMapping("/updateUser")public SysResult updateUser(@RequestBody User user){userService.updateUser(user);return SysResult.success();}

245、编辑UserService及其实现类

void updateUser(User user);

@Overridepublic void updateUser(User user) {//设定当前时间user.setUpdated(new Date());userMapper.updateUser(user);}

246、编辑UserMapper

@Update("update user set phone=#{phone},email=#{email},updated=#{updated} where id=#{id}")void updateUser(User user);

247、用户删除操作,编辑页面JS,删除按钮说明

248、删除JS函数

249、 编辑UserController

/*** 删除数据* URL: /user/{id}* 参数: id* 请求方式: delete* 返回值: SysResult对象*/@DeleteMapping("/{id}")public SysResult deleteById(@PathVariable Integer id){//防止与MP方法冲突 业务方法最好添加业务名称userService.deleteUserById(id);return SysResult.success();}

250、编辑UserService及其实现类

void deleteUserById(Integer id);

@Overridepublic void deleteUserById(Integer id) {userMapper.deleteUserById(id);}

251、编辑UserMapper

@Delete("delete from user where id=#{id}")void deleteUserById(Integer id);

252、全局异常处理

当后台服务器发生异常时,前端用户无法获取异常信息,用户体验差

如果业务代码中添加了大量的try-catch语句,则会导致业务的复杂度变高,不便于维护

Spring的全局异常处理机制

//1.标识该类是全局异常处理机制.返回值都是JSON串// 通知: AOP中的技术,解决特定问题的// 特点: 该异常处理机制,只拦截Controller层抛出的异常@RestControllerAdvicepublic class SystemExe {/*** 说明: 需要为全局异常定义一个方法.* 要求: 返回的统一的业务数据 SysResult* 拦截: 指定遇到某种异常实现AOP处理.* 注意事项: 在业务方法中不要随意添加try-catch*/@ExceptionHandler({RuntimeException.class})public SysResult fail(Exception e){e.printStackTrace();return SysResult.fail();}}

253、Spring中事务控制

事务特性

原子性: 事务要么同时成功,要么同时失败(不可分割)隔离性: 多个事务之间相互独立,互补干扰一致性: 保证数据的一致 (脏读/幻读/不可重复读)持久性: 一旦事务提交,就应该持久化保存.

254、Spring添加事务@Transactional,UserServiceImpl

/*** 问题: 数据是否真的被删除?????* 解决方案: @Transactional* 作用:*1.默认条件下,只拦截运行时异常*2.rollbackFor: 指定异常的类型回滚 rollbackFor = RuntimeException.class*3.noRollbackFor: 指定异常不回滚 noRollbackFor = RuntimeException.class*/@Transactional@Overridepublic void deleteUserById(Integer id) {userMapper.deleteUserById(id);}

255、MybatisPlus,准备新测试环境,新的项目,模板,springboot

256、项目结构

257、ORM知识回顾

核心概念: 对象关系映射,以对象的方式操作数据库.mybatis回顾: Mybatis是半自动化的ORM映射框架.半自动: Sql是自己手写的,但是结果集映射是自动的.MybatisPlus: 全自动的ORM映射框架,对Mybatis的扩展.

258、MP入门案例,导入jar包

<!--mybatis依赖包--><!-- <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version></dependency>--><!--MP内部已经加载了mybatis,所以无需再次添加jar包--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency>

259、编辑POJO对象

@Data@Accessors(chain = true)@NoArgsConstructor@AllArgsConstructor@TableName("demo_user") //对象与表名映射public class User implements Serializable {/*** 规则:* 1.如果数据库中的字段与表中的属性名称一致,则可以省略不写* 2.如果对象名称与表名一致,则名称可以省略*/@TableId(type = IdType.AUTO)//主键自增private Integer id;private String name;//@TableField("age") //实现属性与字段映射private Integer age;private String sex;}

260、编辑UserMapper

public interface UserMapper extends BaseMapper<User> {List<User> findAll();}

261、SpringBoot整合MybatisPlus

MP:是Mybatis的增强版本,只做增强不做改变

编辑application.yml

#SpringBoot整合mybatisPlusmybatis-plus:#指定别名包type-aliases-package: com.jt.pojo#加载指定的xml映射文件mapper-locations: classpath:/mybatis/mappers/*.xml#开启驼峰映射configuration:map-underscore-to-camel-case: true

262、MP入门案例,编辑测试类SpringbootSsmApplicationTests

//效果:只要@Test测试方法执行,则整个Spring容器启动,可以根据自身的需要实现依赖注入//注意事项: 该注解只能在测试类中使用.// 测试类的包路径必须在主启动类的同包及子包中编辑.@SpringBootTestclass SpringbootSsmApplicationTests {@Autowiredprivate UserMapper userMapper;/*** MP入门案例*/@Testpublic void insertUser() {User user = new User();user.setId(null).setName("MybatisPlus").setAge(10).setSex("男");userMapper.insert(user);}}

263、查看数据库

264、 MybatisPlus工作原理

1. 用户调用接口方法 userMapper.insert(User)方法2. 根据UserMapper的接口找到父级接口BaseMapper<T>3. 根据父级接口动态获取当前接口的泛型对象T4. 根据泛型T 获取指定的注解@TableName("demo_user"),之后获取表名demo_user5. 根据泛型对象T,获取其中的属性,之后再找到属性的注解@TableField("id"),之后再次获取注解的值, 即字段名称.6. 根据字段名称,获取对应属性的值.7. 根据Sql拼接 形成最终的可以执行的Sql.8. MP将生成的Sql交给Mybatis执行入库操作.

265、MybatisPlus API介绍,编辑测试类,根据id查询数据

/*** 学习技巧: MP设计思想!!!! 对象* 查询Id=1的用户*/@Testpublic void selectById() {int id = 271;User user = userMapper.selectById(id);System.out.println(user);}

266、编辑测试类,根据name和sex查询数据

/*** 查询name="火灵儿",sex="女"的用户* 规则: 根据对象中不为null的属性进行业务操作* 语法:*1.QueryWrapper条件构造器 动态拼接where条件*2.默认的关系连接符 and* 例子:*select * from demo_user where xx=xx and xx=xx*/@Testpublic void selectByNS() {User user = new User();user.setName("火灵儿").setSex("女");QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);List<User> list = userMapper.selectList(queryWrapper);System.out.println(list);}

267、编辑测试类,利用queryWrapper查询数据

/*** 查询name="比比东",sex="女"的用户* 方式2: 利用条件构造器,构建条件* 说明:*1. eq =*2. gt >*3. lt >*4. ge >=*5. le <=*6. ne <>*/@Testpublic void selectByNS2() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("name","比比东").eq("sex","女");List<User> list = userMapper.selectList(queryWrapper);System.out.println(list);}/*** 需求: 查询age>18岁的用户,并且sex=男.*/@Testpublic void selectByAS() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.gt("age",18).eq("sex","男");List<User> list = userMapper.selectList(queryWrapper);System.out.println(list);}

268、编辑测试类,like关键字

/*** 需求: 查询name中包含"君",性别="女"* Sql: where name like "%君%"* 需求2: 查询name中以"君"结尾的,性别="女" like "%君"*/@Testpublic void selectLike() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();//queryWrapper.like("name","君") //"%君%"queryWrapper.likeLeft("name","君") //"%君".eq("sex","女");List<User> list = userMapper.selectList(queryWrapper);System.out.println(list);}

269、编辑测试类,in关键字

/*** 需求: 查询id=1,3,4,5的数据 并且按照年龄降序排列* 规则: 基本类型有没有方法? 所以使用包装类型*面向对象开发*/@Testpublic void selectIds() {Integer[] ids = {1,3,4,5};QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.in("id",ids).orderByDesc("age");List<User> list = userMapper.selectList(queryWrapper);System.out.println(list);}

270、编辑测试类,查询第一列字段

/*** 需求:* 只想获取第一列数据(主键),sex="女"* 用法: .selectObjs(queryWrapper);* 实际用途: 做关联查询时可以使用*/@Testpublic void selectObjs() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("sex","女");List list = userMapper.selectObjs(queryWrapper);System.out.println(list);}

271、编辑测试类,动态sql实现

/*** 说明: 根据不为null的属性当做where 动态sql实现* 需求: 查询age>18岁,sex=女的用户* 参数说明:* 1. boolean condition, true时,当前的条件才会成立* false 该条件不拼接.* 2.R column 字段信息* 3.Object val 值* 判断字符串API:*Spring提供的API StringUtils.hasLength(sex);*/@Testpublic void selectList2() {Integer age = 20;String sex = "女";//boolean flag = sex !=null && "".equals(sex);boolean flag = StringUtils.hasLength(sex);QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.gt(age!=null, "age",age ).eq(flag,"sex",sex);List<User> list = userMapper.selectList(queryWrapper);System.out.println(list);}

272、商品分类实现,item_cat表

273、项目改造,导入jar包

<!--MP内部已经加载了mybatis,所以无需再次添加jar包--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency>

274、编辑ItemCat

@Data@Accessors(chain = true)@TableName("item_cat")public class ItemCat extends BasePojo {@TableId(type = IdType.AUTO) //主键自增private Integer id; //定义主键private Integer parentId; //定义父级菜单private String name; //分类名称private Boolean status;//分类状态 0 停用 1 正常private Integer level;//商品分类等级 1 2 3@TableField(exist = false)//属性sql不负责操作private List<ItemCat> children; //业务属性}

275、编辑ItemCatMapper

public interface ItemCatMapper extends BaseMapper<ItemCat> {//CURD操作如果没有特殊需求可以省略//如果没有sql的需求,则xml映射文件可以简化}

276、编辑application.yml

#SpringBoot整合MPmybatis-plus:#指定别名包type-aliases-package: com.jt.pojo#加载指定的xml映射文件mapper-locations: classpath:/mybatis/mappers/*.xml#开启驼峰映射configuration:map-underscore-to-camel-case: true

277、项目结构

278、商品分类页面跳转

279、商品分类列表展现,页面分析,生命周期函数,ItemCat.vue

280、调用业务函数

281、编辑ItemCatController

@RestController@CrossOrigin@RequestMapping("/itemCat")public class ItemCatController {@Autowiredprivate ItemCatService itemCatService;/*** 需求: 查询3级分类数据信息* 类型: get* URL: /itemCat/findItemCatList/{level}* 参数: level* 返回值: SysResult(list)*/@GetMapping("/findItemCatList/{level}")public SysResult findItemCatList(@PathVariable Integer level){List<ItemCat> list = itemCatService.findItemCatList(level);return SysResult.success(list);}}

282、编辑ItemCatService及其实现类(常规写法-效率低)

public interface ItemCatService {List<ItemCat> findItemCatList(Integer level);}

@Servicepublic class ItemCatServiceImpl implements ItemCatService {@Autowiredprivate ItemCatMapper itemCatMapper;/*** 弊端: 由于多次循环遍历 查询数据库,导致数据库查询次数太多效率极低.* 思路:*1.刚才的业务逻辑梳理*2.如何优化????? 提高效率* @param level* @return*/@Overridepublic List<ItemCat> findItemCatList(Integer level) {//查询一级商品分类信息QueryWrapper<ItemCat> queryWrapper = new QueryWrapper<>();queryWrapper.eq("parent_id",0);List<ItemCat> oneList = itemCatMapper.selectList(queryWrapper);//查询二级商品分类信息for(ItemCat oneItemCat: oneList){//1.为了复用条件构造器 将之前的数据清空queryWrapper.clear();//查询二级数据 parent_id = 一级IDqueryWrapper.eq("parent_id",oneItemCat.getId());List<ItemCat> twoList = itemCatMapper.selectList(queryWrapper);//遍历二级列表 查询三级数据,封装数据返回oneItemCat.setChildren(twoList);}return oneList;}}

283、商品分类页面显示

284、商品分类列表优化,Map封装策略

遍历数据,如果该数据的父级不存在,准备list集合,将自己作为第一个元素

遍历数据,如果该数据的父级存在,获取list集合,将自己追加到其中

封装Map集合,编辑ItemCatServiceImpl

/*** 优化手段:*思路:获取所有的数据库记录,之后按照父子级关系进行封装*数据结构: Map<k,v>*Map<parentId,List当前父级的子级信息(不嵌套)>*例子:Map<0,List[{id=1,name="xx",children=null}.....]>** 封装数据规则:*1.遍历所有的数据.*2.获取parentId*3.判断parentId是否存在,之后实现数据封装*/public Map<Integer,List<ItemCat>> getMap(){Map<Integer,List<ItemCat>> map = new HashMap<>();//查询所有的数据库记录List<ItemCat> list = itemCatMapper.selectList(null);//1.遍历数据for(ItemCat itemCat:list){int parentId = itemCat.getParentId();if(map.containsKey(parentId)){//表示数据存在,将自己追加map.get(parentId).add(itemCat);}else{//key不存在, 定义list集合,将自己作为第一个元素追加List<ItemCat> childrenList = new ArrayList<>();childrenList.add(itemCat);//将数据保存到map集合中map.put(parentId,childrenList);}}return map;}

285、获取二级数据信息

//该方法获取1-2级数据信息public List<ItemCat> getTwoList(Map<Integer,List<ItemCat>> map){//1.先查询一级菜单数据List<ItemCat> oneList = map.get(0);//2.遍历每个一级菜单去封装二级数据for(ItemCat oneItemCat : oneList){//parent_id = 一级IDint parentId = oneItemCat.getId();//查询二级数据List<ItemCat> twoList = map.get(parentId);//将数据进行封装oneItemCat.setChildren(twoList);}//返回一级数据return oneList;}

286、商品分类全部数据获取

@Servicepublic class ItemCatServiceImpl implements ItemCatService {@Autowiredprivate ItemCatMapper itemCatMapper;/*** 弊端: 由于多次循环遍历 查询数据库,导致数据库查询次数太多效率极低.* 思路:*1.刚才的业务逻辑梳理*2.如何优化????? 提高效率* @param level* @return*/@Overridepublic List<ItemCat> findItemCatList(Integer level) {//查询一级商品分类信息QueryWrapper<ItemCat> queryWrapper = new QueryWrapper<>();queryWrapper.eq("parent_id",0);List<ItemCat> oneList = itemCatMapper.selectList(queryWrapper);//查询二级商品分类信息for(ItemCat oneItemCat: oneList){//1.为了复用条件构造器 将之前的数据清空queryWrapper.clear();//查询二级数据 parent_id = 一级IDqueryWrapper.eq("parent_id",oneItemCat.getId());List<ItemCat> twoList = itemCatMapper.selectList(queryWrapper);//遍历二级列表 查询三级数据,封装数据返回oneItemCat.setChildren(twoList);}return oneList;}/*** 优化手段:*思路:获取所有的数据库记录,之后按照父子级关系进行封装*数据结构: Map<k,v>*Map<parentId,List当前父级的子级信息(不嵌套)>*例子:Map<0,List[{id=1,name="xx",children=null}.....]>** 封装数据规则:*1.遍历所有的数据.*2.获取parentId*3.判断parentId是否存在,之后实现数据封装*/public Map<Integer,List<ItemCat>> getMap(){Map<Integer,List<ItemCat>> map = new HashMap<>();//查询所有的数据库记录List<ItemCat> list = itemCatMapper.selectList(null);//1.遍历数据for(ItemCat itemCat:list){int parentId = itemCat.getParentId();if(map.containsKey(parentId)){//表示数据存在,将自己追加map.get(parentId).add(itemCat);}else{//key不存在, 定义list集合,将自己作为第一个元素追加List<ItemCat> childrenList = new ArrayList<>();childrenList.add(itemCat);//将数据保存到map集合中map.put(parentId,childrenList);}}return map;}//该方法获取1-2级数据信息public List<ItemCat> getTwoList(Map<Integer,List<ItemCat>> map){//1.先查询一级菜单数据List<ItemCat> oneList = map.get(0);//2.遍历每个一级菜单去封装二级数据for(ItemCat oneItemCat : oneList){//parent_id = 一级IDint parentId = oneItemCat.getId();//查询二级数据List<ItemCat> twoList = map.get(parentId);//将数据进行封装oneItemCat.setChildren(twoList);}//返回一级数据return oneList;}/*** 实现思路:*1. 获取二级分类列表信息*2. 遍历一级菜单,获取二级数据*3. 根据二级菜单查询三级数据 防止二级数据为null的现象*4. 将三级数据封装到二级中* @param map* @return*/public List<ItemCat> getThreeList(Map<Integer,List<ItemCat>> map){//1.获取1-2数据信息 包含了2级的childrenList<ItemCat> oneList = getTwoList(map);//2.编辑一级数据,获取二级数据for(ItemCat oneItemCat : oneList){List<ItemCat> twoList = oneItemCat.getChildren();if(twoList == null || twoList.size()==0){//跳过本地循环,进入下一次循环continue;}//3.遍历二级数据,查询三级信息for (ItemCat twoItemCat : twoList){//查询三级 parentId = 二级IDint parentId = twoItemCat.getId();List<ItemCat> threeList = map.get(parentId);//将三级封装到二级中twoItemCat.setChildren(threeList);}}return oneList;}/*** 如果使用常规的写法 耗时: 900毫秒* 经过优化: 20毫秒* CURD: 好代码!!!* @param level* @return*/@Overridepublic List<ItemCat> findItemCatList2(Integer level) {long startTime = System.currentTimeMillis();//获取所有集合数据Map<Integer,List<ItemCat>> map = getMap();if(level == 1){//1.一级商品分类信息return map.get(0);}//获取一级菜单和二级菜单if(level == 2){return getTwoList(map);}//获取三级菜单数据 1-2-3List<ItemCat> allList = getThreeList(map);long endTime = System.currentTimeMillis();System.out.println("耗时:"+(endTime-startTime)+"毫秒");return allList;}}

287、展现效果

288、商品分类新增,页面分析

如果只写商品分类名称,则表示一级菜单

如果父级分类为一级时,则表示二级菜单

如果父级分类为二级时,则表示三级菜单

289、页面的确定按钮

290、页面JS函数

291、编辑ItemCatController

/*** 实现商品分类新增操作* URL: /itemCat/saveItemCat* 参数: this.itemCatForm JSON* 请求类型: post* 返回值: SysResult对象*/@PostMapping("/saveItemCat")public SysResult saveItemCat(@RequestBody ItemCat itemCat){itemCatService.saveItemCat(itemCat);return SysResult.success();}

292、编辑BasePojo

@Data@Accessors(chain = true)public class BasePojo implements Serializable {@TableField(fill = FieldFill.INSERT)//表示入库时需要赋值private Date created;@TableField(fill = FieldFill.INSERT_UPDATE)//表示入库/更新时赋值private Date updated;}

293、编辑ItemCatService及其实现类

void saveItemCat(ItemCat itemCat);

@Override@Transactionalpublic void saveItemCat(ItemCat itemCat) {Date date = new Date();itemCat.setStatus(true).setCreated(date).setUpdated(date);itemCatMapper.insert(itemCat);}

294、新增显示

295、商品分类删除

如果不是父级则直接删除,如果是父级,则先删除子级

页面按钮

296、删除JS函数

297、编辑ItemCatController

/*** 需求: 实现商品分类删除操作* 类型: delete* URL: /itemCat/deleteItemCat?id=xx&level=xx* 参数: id/level* 返回值: SysResult*/@DeleteMapping("/deleteItemCat")public SysResult deleteItemCat(ItemCat itemCat){itemCatService.deleteItemCat(itemCat);return SysResult.success();}

298、编辑ItemCatService及其实现类

void deleteItemCat(ItemCat itemCat);

/*** 业务: 如果是父级 则应该删除子级和自己.* 思路:*1. 判断是否为3级标签 直接删除*2. 判断是否为2级标签 先删除三级再删除二级*3. 判断是否为1级标签 先查询二级,再删除三级和二级再删除一级* @param itemCat*/@Override@Transactionalpublic void deleteItemCat(ItemCat itemCat) {if(itemCat.getLevel() == 3){int id = itemCat.getId();itemCatMapper.deleteById(id);return;}if(itemCat.getLevel() == 2){ //id=二级id//Sql: xxx where parent_id = 二级IDint id = itemCat.getId();QueryWrapper<ItemCat> queryWrapper = new QueryWrapper<>();queryWrapper.eq("parent_id",id);//删除的是三级数据itemCatMapper.delete(queryWrapper);//再删除自己itemCatMapper.deleteById(id);return;}/*** 删除一级菜单*///1.查询二级数据 Sql: where parent_id=idQueryWrapper queryWrapper = new QueryWrapper();int id = itemCat.getId();queryWrapper.eq("parent_id",id);//由于是删除的业务,只需要获取id即可 所以使用objsList idList = itemCatMapper.selectObjs(queryWrapper);//判断是否有二级数据.如果有直接删除.如果没有直接删除一级if(idList.size()>0){//根据二级Id删除三级数据 Sql where parent_id in (1,2,3)queryWrapper.clear();queryWrapper.in("parent_id",idList);itemCatMapper.delete(queryWrapper);//将所有的1-2级的ID,封装到一个集合中idList.add(id);//将所有1级2级全部删除 batch 实质就是in关键字itemCatMapper.deleteBatchIds(idList);}else{itemCatMapper.deleteById(id);}}

299、编辑BasePojo,自动填充时间

@Data@Accessors(chain=true)public class BasePojo implements Serializable{//新增操作时 自动填充@TableField(fill = FieldFill.INSERT)private Date created;//新增和修改操作时自动填充@TableField(fill = FieldFill.INSERT_UPDATE)private Date updated;}

300、编辑config配置

@Component //将对象交给Spring容器管理public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {Date date = new Date();this.setFieldValByName("created",date,metaObject);this.setFieldValByName("updated",date,metaObject);}@Overridepublic void updateFill(MetaObject metaObject) {this.setFieldValByName("updated",new Date(),metaObject);}}

301、自动填充代码测试,编辑ItemCatServiceImpl里面的saveItemCat方法

@Override@Transactionalpublic void saveItemCat(ItemCat itemCat) {//Date date = new Date();//itemCat.setStatus(true).setCreated(date).setUpdated(date);itemCat.setStatus(true);itemCatMapper.insert(itemCat);}

302、状态修改,页面JS

303、编辑ItemCatController

/*** 需求:修改状态* URL: /itemCat/status/{id}/{status}* 参数: id/status* 请求类型: put* 返回值: SysResult*/@PutMapping("/status/{id}/{status}")public SysResult updateStatus(ItemCat itemCat){itemCatService.updateStatus(itemCat);return SysResult.success();}

304、编辑ItemCatService及其实现类

void updateStatus(ItemCat itemCat);

/*** id/status* Sql: update item_cat set status=xx,updated=xx* where id=xx* 解释: updateById ID当做唯一where条件,其它不为null的属性* 当做set条件*/@Overridepublic void updateStatus(ItemCat itemCat) {itemCatMapper.updateById(itemCat);}

305、修改一下ItemCatServiceImpl里面的findItemCatList,也可以查询到所有数据

/*** 弊端: 由于多次循环遍历 查询数据库,导致数据库查询次数太多效率极低.* 思路:*1.刚才的业务逻辑梳理*2.如何优化????? 提高效率* @param level* @return*/@Overridepublic List<ItemCat> findItemCatList(Integer level) {long startTime = System.currentTimeMillis();//查询一级商品分类信息QueryWrapper<ItemCat> queryWrapper = new QueryWrapper<>();queryWrapper.eq("parent_id",0);List<ItemCat> oneList = itemCatMapper.selectList(queryWrapper);//查询二级商品分类信息for(ItemCat oneItemCat: oneList){//1.为了复用条件构造器 将之前的数据清空queryWrapper.clear();//查询二级数据 parent_id = 一级IDqueryWrapper.eq("parent_id",oneItemCat.getId());List<ItemCat> twoList = itemCatMapper.selectList(queryWrapper);//遍历二级列表 查询三级数据,封装数据返回oneItemCat.setChildren(twoList);//查询三级商品分类信息for(ItemCat twoItemCat: twoList){//1.为了复用条件构造器 将之前的数据清空queryWrapper.clear();//查询三级数据 parent_id = 二级IDqueryWrapper.eq("parent_id",twoItemCat.getId());List<ItemCat> threeList = itemCatMapper.selectList(queryWrapper);//遍历二级列表 查询三级数据,封装数据返回twoItemCat.setChildren(threeList);}}long endTime = System.currentTimeMillis();System.out.println("耗时:"+(endTime-startTime)+"毫秒");return oneList;}

306、商品分类修改,页面JS分析

307、修改的JS

308、修改的JS函数

309、编辑ItemCatController

/*** 需求: 修改商品分类信息* URL: /itemCat/updateItemCat* 参数: 表单数据 ItemCat对象 {id,name,parentId....}* 类型: put* 返回值: SysResult对象*/@PutMapping("/updateItemCat")public SysResult updateItemCat(@RequestBody ItemCat itemCat){itemCatService.updateItemCat(itemCat);return SysResult.success();}

310、编辑ItemCatService及其实现类

void updateItemCat(ItemCat itemCat);

/*** itemCat对象,不为null的数据执行业务* 只改了name属性 set name=xxx where id=xx* @param itemCat*/@Overridepublic void updateItemCat(ItemCat itemCat) {ItemCat temp = new ItemCat();temp.setId(itemCat.getId()).setName(itemCat.getName());itemCatMapper.updateById(temp);}

311、商品业务模块实现,实现路由跳转,router/index.js

312、 页面效果展现

313、商品模块搭建,Item表,价格扩大100倍之后的数据

314、编辑Item

@Data@Accessors(chain = true)@TableName("item") //映射表public class Item extends BasePojo {@TableId(type = IdType.AUTO)private Integer id; //商品Id号private String title; //商品标题信息private String sellPoint; //卖点信息private Integer price;//商品价格private Integer num; //商品数量private String images; //商品图片private Integer itemCatId; //商品分类ID号private Boolean status;//状态信息 0 下架 1 上架}

315、编辑ItemMapper

public interface ItemMapper extends BaseMapper<Item> {}

316、构建层级代码

317、商品列表展现,页面分析,调用生命周期函数

318、检查JS函数

319、编辑ItemController

@RestController@CrossOrigin@RequestMapping("/item")public class ItemController {@Autowiredprivate ItemService itemService;/*** 业务: 实现商品列表分页展现* 类型: get* url: /item/getItemList?query=&pageNum=1&pageSize=10* 参数: pageResult* 返回值: SysResult(pageResult)*/@GetMapping("/getItemList")public SysResult getItemList(PageResult pageResult){//3pageResult = itemService.getItemList(pageResult);return SysResult.success(pageResult);}}

320、编辑ItemService及其实现类

public interface ItemService {PageResult getItemList(PageResult pageResult);}

@Servicepublic class ItemServiceImpl implements ItemService {@Autowiredprivate ItemMapper itemMapper;/*** 语法:selectPage语法说明*1.page: MP内部指定的分页对象*2.queryWrapper 条件构造器*Sql: where title like "%xxx%"* @param pageResult* @return*/@Overridepublic PageResult getItemList(PageResult pageResult) {//判断用户的数据是否有值boolean flag = StringUtils.hasLength(pageResult.getQuery());QueryWrapper<Item> queryWrapper = new QueryWrapper<>();queryWrapper.like(flag,"title",pageResult.getQuery());//编辑MP的分页对象 四个属性有用(页数/条数/总数/记录) 传递=页数/条数IPage<Item> page = new Page<>(pageResult.getPageNum(),pageResult.getPageSize());page = itemMapper.selectPage(page,queryWrapper);//获取总数long total = page.getTotal();//获取记录数List<Item> rows = page.getRecords();//将数据封装return pageResult.setTotal(total).setRows(rows);}}

321、MP实现分页配置类

需要指定的数据库类型,按照MP的基本结构进行配置

//什么是bean spring容器管理的对象叫做bean@Configuration //标识这是一个配置类 相当于早期的xml文件public class MybatisPlusConfig {/*** @Bean作用: 将方法的返回值交给Spring容器管理* @return*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MARIADB));return interceptor;}}

322、页面效果展现

323、商品新增,编辑路由

324、商品新增,页面JS函数分析

325、封装ItemVO对象

@Data@Accessors(chain = true)@NoArgsConstructor@AllArgsConstructorpublic class ItemVO { //该对象封装商品所有的参数信息private Item item;private ItemDesc itemDesc;}

326、编辑ItemController

/*** 需求: 实现商品新增* URL: http://localhost:8091/item/saveItem* 参数: {item:this.addItemForm,itemDesc:this.itemDesc }* 类型: post* 接收数据: ItemVO* 返回值: SysResult对象*/@PostMapping("/saveItem")public SysResult saveItem(@RequestBody ItemVO itemVO){itemService.saveItem(itemVO);return SysResult.success();}

327、编辑ItemService及其实现类

void saveItem(ItemVO itemVO);

@Overridepublic void saveItem(ItemVO itemVO) {Item item = itemVO.getItem();item.setStatus(true);itemMapper.insert(item);}

328、页面效果展现

329、富文本编辑器,页面JS说明

330、组件引用,main.js

331、已安装

332、实现商品详情入库,ItemDesc说明

说明: item表是商品的基本信息,itemDesc表是商品的详情信息. 用户一般查询时都是查询的基本信息.只有点击某个商品时才会查询详情信息.为了提高查询效率 将商品分为 item/itemDesc逻辑关系:1. 一个商品对应一个详情2. 一个详情对应一个商品数据库表示: item.id = itemDesc.id

333、商品详情参数传递

当用户点击添加商品时,会将item/itemDesc的对象进行传递,则在后端动态接收数据则可以获取2个对象数据

addItem.vue页面的addItemBtn函数

334、编辑ItemDesc

@Data@Accessors(chain = true)@TableName("item_desc")public class ItemDesc extends BasePojo {//由于item.id=itemDesc.id 所以ID不能主键自增@TableIdprivate Integer id;private String itemDesc;}

335、编辑ItemDescMapper

public interface ItemDescMapper extends BaseMapper<ItemDesc> {}

336、编辑ItemServiceImpl里面的saveItem方法

当用户点击入库时,应该将item/itemDesc一起入库操作

@Override@Transactionalpublic void saveItem(ItemVO itemVO) {Item item = itemVO.getItem(); //id=nullitem.setStatus(true);//要求item入库之后,动态返回Id!!!!//MP原则: 入库之后动态回显数据!!itemMapper.insert(item);//实现itemDesc对象入库ItemDesc itemDesc = itemVO.getItemDesc();itemDesc.setId(item.getId());itemDescMapper.insert(itemDesc);}

337、文件上传,图片上传UI

338、请求路径说明

339、编辑ImageVO

@Data@Accessors(chain = true)@NoArgsConstructor@AllArgsConstructorpublic class ImageVO {private String virtualPath; //图片实际目录private String urlPath;//请求路径private String fileName; //图片名称}

340、编辑FileController

@RestController@CrossOrigin@RequestMapping("/file")public class FileController {/*** 需求: 实现文件上传* URL地址: "http://localhost:8091/file/upload",* 参数: file=xxxx* 类型: POST请求* 返回值: SysResult(ImageVO)* 基础知识:*inputStream,outputStream* 高级API: SpringMVC MultipartFile* 需求: 接收用户信息,保存到本地磁盘中* 控制图片大小: 默认大小1M*/@PostMapping("/upload")public SysResult upload(MultipartFile file) throws IOException {//1.获取图片的名称String fileName = file.getOriginalFilename();//2.封装文件上传目录String fileDir = "D:/Java/File/images";//3.检查目录是否存在File dir = new File(fileDir);if(!dir.exists()){//如果目录不存在//如果目录不存在,则创建目录dir.mkdirs();}//4.封装文件的全路径String path = fileDir + "/" +fileName;//5.上传文件file.transferTo(new File(path));return SysResult.success();}}

341、编辑FileController

/*** 需求: 实现文件上传* URL地址: "http://localhost:8091/file/upload",* 参数: file=xxxx* 类型: POST请求* 返回值: SysResult(ImageVO)* 基础知识:*inputStream,outputStream* 高级API: SpringMVC MultipartFile* 需求: 接收用户信息,保存到本地磁盘中* 控制图片大小: 默认大小1M*/@PostMapping("/upload")public SysResult upload2(MultipartFile file){ImageVO imageVO = fileService.upload(file);if(imageVO == null){return SysResult.fail();}return SysResult.success(imageVO);}

342、编辑FileService及其实现类

public interface FileService {ImageVO upload(MultipartFile file);}

@Servicepublic class FileServiceImpl implements FileService {private String localDir = "D:/Java/File/images";private String urlPath = "";/*** 考虑的问题:*1. 校验图片类型 xx.jpg*2. 校验是否为恶意程序 xx.exe.jpg*3. 将文件分目录存储.*4. 为了保证图片唯一性 ,UUID* @param file* @return*/@Overridepublic ImageVO upload(MultipartFile file) {//xxxxxx.jpg|png|gif 防止大小写问题,将所有字母转化为小写String fileName = file.getOriginalFilename().toLowerCase();//利用正则判断是否为图片if(!fileName.matches("^.+\\.(jpg|png|gif)$")){//如果校验不通过,则终止程序return null;}System.out.println("图片类型正确的!!!!!!");//第二步 防止恶意程序 判断图片是否有宽度和高度try {BufferedImage bufferedImage = ImageIO.read(file.getInputStream());int width = bufferedImage.getWidth();int height = bufferedImage.getHeight();if(width == 0 || height == 0){return null;}System.out.println("用户上传的是图片");//第三步: 目录如何划分 yyyy/MM/ddString dateDir = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());// E:/images + //11/11/ 拼接目录String dirPath = localDir + dateDir;File dirFile = new File(dirPath);if(!dirFile.exists()){//如果目录不存在时, 创建目录dirFile.mkdirs();}//第四步: 使用uuid实现文件名称 uuid.jpg//4.1 生成UUIDString uuid = UUID.randomUUID().toString().replace("-","");//截取文件类型int index = fileName.lastIndexOf(".");String fileType = fileName.substring(index);//生成新文件名称String newFile = uuid + fileType;//第五步:实现文件上传 全路径 再上传// E:/images//10/15/uuid.jpgString path = dirPath + newFile;file.transferTo(new File(path));System.out.println("文件上传成功!!!!");//第六步: 返回ImageVO数据//6.1 虚拟路径只写动态变化的数据 //11/11/uuid.jpgString virtualPath = dateDir + newFile;//6.2 真实图片名称String fileNameVO = newFile;//6.3 网络地址 /xx/uuid.jpgString url = urlPath + virtualPath;return new ImageVO(virtualPath,url,fileNameVO);} catch (IOException e) {e.printStackTrace();return null;}}}

343、关于磁盘地址与网络地址的说明

磁盘地址:用户将图片上传到本地磁盘中 有磁盘地址.D:/Java/File/images//10/15/a.jpg网络地址:准备一个可以通过网络访问服务器的一个固定的地址.该地址指向真实的磁盘地址,即可以看到该图片//10/15/a.jpg

344、文件删除操作,页面JS分析

345、 编辑FileController

/*** 需求: 删除图片信息* url: http://localhost:8091/file/deleteFile* 类型: delete* 参数: virtualPath* 返回值: SysResult对象*/@DeleteMapping("/deleteFile")public SysResult deleteFile(String virtualPath){fileService.deleteFile(virtualPath);return SysResult.success();}

346、编辑FileService及其实现类

public interface FileService {ImageVO upload(MultipartFile file);void deleteFile(String virtualPath);}

/*** 1.准备全文件路径* 2.实现文件删除* @param virtualPath*/@Overridepublic void deleteFile(String virtualPath) {String path = localDir + virtualPath;File file = new File(path);if(file.exists()){//如果文件存在,则删除文件file.delete();}}

347、代理机制

反向代理

反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源。同时,用户不需要知道目标服务器的地址,也无须在用户端作任何设定。反向代理服务器通常可用来作为Web加速,即使用反向代理作为Web服务器的前置机来降低网络和服务器的负载,提高访问效率

反向代理特点

代理服务器介于用户和服务器之间.

用户以为反向代理服务器就是目标服务器.

用户不清楚真实的服务器到底是谁!

反向代理服务器保护了目标服务器的信息 所以也称之为"服务器端代理".

正向代理

正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。

正向代理特点

正向代理服务器介于用户和服务器之间

用户将请求发送给代理服务器,并且指定目标服务器.

目标服务器以为是代理服务器访问的,保护了用户的信息,所以也称之为 “客户端代理”

正向和反向代理特点

用户的每一次请求都包含了正向代理和反向代理机制.

348、Nginx服务器介绍

Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于10月4日。

其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、简单的配置文件和低系统资源的消耗而闻名。6月1日,nginx 1.0.4发布。

Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。

Nginx特点

1. 占有内存少 运行时内存占用量不超过2M

2. 并发能力强 官网测试数据 5万次/秒 实测 3万次/秒

tomcat服务器 并发能力 150-220左右 1000/秒

扩展: F5 负载均衡服务器 运营商一般使用 20万/秒

Nginx下载

选右边的Windows版本,下载下来之后解压

/en/download.html

Nginx安装说明

nginx路径说明

路径问题:

nginx是c语言开发的所以对中文不友好. 额外需要注意空格

端口问题:

1.Nginx运行的端口是80. 80端口不能被其它的服务占用.

2.如果80端口被其它的服务占用,则通过dos命令 kill 杀死进程.

占用端口:

http协议默认端口号80端口.

https协议默认端口号443端口

nginx进程项说明

nginx 每次启动都会有2个进程. 一个主进程, 一个是守护进程

主进程: 主要提供反向代理服务. 占用内存空间大

守护进程: 防止主进程意外关闭的.

如果需要关闭nginx 则先关闭守护 再关闭主进程.

nginx启动占用端口80,所以需要释放80资源

查询80端口被哪个进程占用

netstat -ano | findstr "80"

检查nginx启动是否正常,访问:localhost

nginx命令(必须掌握)

说明: 要求执行nginx 命令 应该在nginx.exe所在目录执行.

命令:

1. start nginx 启动nginx

2. nginx -s reload 重启nginx 只有nginx启动时才可以重启

3. nginx -s stop 停止nginx

注意事项: nginx的运行只能启动一次,如果启动多次则会产生多余项,影响程序的正常运行

349、Nginx反向代理说明

#Nginx只能支持http/httpshttp {#反向代理服务 一个服务一个serverserver {#监听端口 一般都是80listen 80;#拦截的域名 server_name localhost;# 进行反向代理服务配置 # / 根目录 拦截用户所有的请求location / {#root关键字 代理的是一个目录root html;# 默认访问的页面index index.html index.htm;}}}

350、图片回显

磁盘地址: D:\Java\File\images\\10\15\a.jpg

网络地址: \\10\15\a.jpg

代理核心: 映射到 D:\Java\File\images

实现域名代理,编辑conf目录下的nginx.conf:

注意事项:

1. start nginx 命令 如果配置文件有错, 不会提示.

2. nginx -s reload 重启命令 会有错误提示

351、图片回显原理

根据hosts文件可以实现域名与IP的映射关系,在本机实现域名与IP的映射,只对本机有效

修改hosts文件

位置:C:\Windows\System32\drivers\etc

如果勾选只读,则去掉

352、编辑hosts文件

353、hosts测试,启动后台服务器, 访问::8091/rights/getRightsList

354、后台运行,前台运行,Nginx启动,页面效果展现

355、查看本地目录中的文件

356、京淘项目前端发布

前端组成部分

原始文件-开发阶段:1. node.js2. 脚手架项目3. Vue组件4. Vue路由5. Axios ajax请求.项目发布阶段:1.html2.css样式3.js说明: 如果前端项目需要发布项目,则将项目打包部署即可.

357、前端部署准备工作

路径说明

前端向后端发送请求时路径都是 http://localhost:8091/xxx/xxx,该请求需要转化为网络地址. /xxx/xxx图片上传的地址 http://localhost:8091 换为

358、修改ajax请求地址,修改main.js

359、修改addItem.vue

360、项目前端发布

任务,build,运行,对号

361、发布之后的文件位置,dist

362、复制到nginx的根目录

363、前端项目发布

用户通过域名: :80 访问前端的项目路径 dist/index.html

编辑nginx.conf文件

364、http协议自动转化为https问题

开发: 使用谷歌浏览器 最为标准的浏览器

解决方案:

1.浏览器中输入: “chrome://net-internals/#hsts:“

2.删除指定的域名

365、清空浏览器缓存,然后重启

366、访问:/#/login(有问题)

367、实现域名的代理

后端请求的网址: 转向到 http://localhost:8091

代理规则: 反向代理.

368、修改之后,重启nginx(出现问题)

369、Nginx实现负载均衡

动态获取端口号,编辑PortController

@RestController@CrossOriginpublic class PortController {@Value("${server.port}")private Integer port;//动态获取端口号@GetMapping("/getPort")public String getPort(){return "当前端口号:" + port;}}

370、关闭热部署

说明: 由于需要同时开启2台tomcat服务器,所以需要关闭热部署操作

将POM.xml文件中的热部署jar包去除即可.

<!--热部署,开发阶段有效--><!--<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency>-->

371、修改端口号

先8091启动,再改为8092,更改一下下面的选项,再启动

分别启动2台tomcat服务器. 端口号分别为8091/8092. 通过下图实现进程项执行2次的操作.

访问:http://localhost:8091/getPort

访问:http://localhost:8092/getPort

372、负载均衡策略

373、找到nginx.conf文件

374、编辑nginx.conf,配置后端集群,并更改上面的代理

#:80 映射localhost:8091server {listen 80;server_name ;location / {#代理请求#proxy_pass http://127.0.0.1:8091;proxy_pass http://tomcats;}}#配置后端集群upstream tomcats {server 127.0.0.1:8091;server 127.0.0.1:8092;}

375、保存,启动一下nginx,在有nginx.exe文件夹上cmd,start nginx

376、访问:/getPort

刷新

377、负载均衡策略

轮询策略

根据配置文件内容,依次访问服务器

#:80 映射localhost:8091server {listen 80;server_name ;location / {#代理请求#proxy_pass http://127.0.0.1:8091;proxy_pass http://tomcats;}}#配置后端集群upstream tomcats {server 127.0.0.1:8091;server 127.0.0.1:8092;}

权重策略(十年以前,现在是微服务的轮询)

根据服务器的性能,手动分配服务器的负载

#配置后端集群 1.默认轮询 2.权重 weightupstream tomcats {server 127.0.0.1:8091 weight=4;server 127.0.0.1:8092 weight=1;}

保存,重启nginx

访问:/getPort,8091出现的概率比较多,80%

IPHASH

让用户的请求与服务器绑定,用户访问某台服务器,以后永远访问该服务器

#配置后端集群 1.默认轮询 2.权重 weight 3.iphash策略upstream tomcats {ip_hash; server 127.0.0.1:8091;server 127.0.0.1:8092;}

保存,重启nginx,nginx -s reload,再访问:/getPort,是8091,后面刷新,都是8091

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。