目录
- redis
- 概念
- 下载安装
- 命令操作
- 数据结构
- 持久化操作
- Jedis使用Java客户端操作redis
- 案例
- maven
- 概述
- 优势
- 安装
- 仓库的种类及关系
- 标准目录结构
- 常用命令
- 生命周期
- 概念模型图
- IDEA集成Maven插件
- 使用骨架创建Maven的Java工程
- 不使用骨架创建Maven的Java工程
- 使用骨架创建Maven的JavaWeb工程
- 报错解决:
org.apache.jasper.JasperException: Unable to compile class for JSP:
- 报错解决:jar包冲突
- Maven工程运行环境的修改
- Maven的Java工程操作数据库
开始
一、redis
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。
参考:菜鸟教程
1.1概念
高效的非关系型数据库NoSQL(Not Only SQL)
操作关系型数据库是非常耗时的,经常查询一些不太变化的数据,我们可以利用缓存的思想来解决这个问题
我们从缓存中获取数据:
- 有我们要需要的数据
- 直接返回数据,不需要和数据库交互
- 没有我们需要的数据
- 从数据库查询,将数据库放入缓存
关于缓存的选择,我们可以使用Map集合,但是局限于此台电脑的内存中,将来分布式项目部署就不合适了
因此选择非关系型数据库像redis是合适的
NoSQL型的数据库和关系型的数据库做一个互补
主流的NoSQL产品
Redis介绍
1.2下载安装
官网:http://redis.io
中文网:http://www.redis.net.cn/
下载windows版本的后解压到指定文件夹,打开服务器端,然后在打开客户端
redis端口是6379
1.3命令操作
- 命令操作
- Java代码操作
1.4数据结构
- 字符串类型String
- 哈希类型hash
- 列表类型list
可重复元素
- 集合类型set
元素不能重复
- 有序集合类型sortedset
不允许重复元素,且元素有顺序 - 通用命令
1.5持久化操作
概念
- redis是一个内存数据库,当redis服务器重启,或者电脑重启,数据会丢失
- 我们可以将redis内存中的数据,持久化保存到硬盘文件中
redis持久化机制
- RDB:默认方式,不需要进行配置,默认就是这种机制
在一定的时间间隔内,检测key的变化情况,然后持久化数据 - AOF:日志记录的方式,可以记录每一条命令的操作,可以每一次操作修改数据后就保存
RDB默认方式
具体的参数根据服务器的性能要求来配置,当达到频率要求后,就会在当前目录下持久化生成一个dump.rdb
文件,我们下次可以获取数据
AOF日志记录
先开启AOF机制
遇到的问题:如果持久化失败可能就是 没有打开redis.conf文件,尝试
打开一个cmd窗口 使用cd命令切换目录到 redis的目录 运行 redis-server.exe redis.conf 。
然后打开就出现了
1.6使用Java客户端操作redis
快速入门:
- 导包
- 操作
不同格式数据的操作:
- 字符串格式的数
package henu.soft.xiaosi;
import org.junit.Test;
import redis.clients.jedis.Jedis;
public class JedisTest {
@Test
public void test1(){
//1. 获取连接
Jedis jedis = new Jedis("localhost");//端口号默认6379,地址为localhost
//也可以空参:Jedis jedis = new Jedis();
//2. 操作
jedis.set("username","xiaosi");
//3. 关闭连接
jedis.close();
}
}
可以给指定参数设置存活时间
- hash格式的数据操作
@Test
public void test2(){
//1. 获取连接
Jedis jedis = new Jedis("localhost",6379);
//设置hash
jedis.hset("user","name","xiaosi");
jedis.hset("user","age","20");
jedis.hset("user","gender","男");
//获取hash
String name = jedis.hget("user", "name");
System.out.println(name);
jedis.close();
}
@Test
public void test2(){
//1. 获取连接
Jedis jedis = new Jedis("localhost",6379);
//设置hash
jedis.hset("user","name","xiaosi");
jedis.hset("user","age","20");
jedis.hset("user","gender","男");
//获取hash
//String name = jedis.hget("user", "name");
//System.out.println(name);
//遍历
Map<String, String> user = jedis.hgetAll("user");
Set<String> keys = user.keySet();
for (String key : keys) {
String value = user.get(key);
System.out.println(key + " : " + value );
}
jedis.close();
}
- ist格式的数据操作
//先从左边存,然后右边存
//jedis.lpush("list","a","b","c");这个报错,只能一次push一个
jedis.lpush("list","a");
jedis.rpush("list","b");
//获取
List<String> list = jedis.lrange("list", 0, -1);
System.out.println(list);
@Test
public void test3(){
//1. 获取连接
Jedis jedis = new Jedis("localhost",6379);
//先从左边存,然后右边存
//jedis.lpush("list","a","b","c");这个报错,只能一次push一个
jedis.lpush("list","a");
jedis.lpush("list","b");
jedis.rpush("list","c");
//获取
List<String> list = jedis.lrange("list", 0, -1);
System.out.println(list);
String del1 = jedis.lpop("list");
String del2 = jedis.rpop("list");
System.out.println(del1);
System.out.println(del2);
List<String> new_list = jedis.lrange("list", 0, -1);
System.out.println(new_list);
jedis.close();
}
- set格式数据操作
@Test
public void test4(){
//1. 获取连接
Jedis jedis = new Jedis("localhost",6379);
//set存储
jedis.sadd("myset","java","php","c++");
//获取set全部value
Set<String> myset = jedis.smembers("myset");
System.out.println(myset);
jedis.close();
}
- sortedset数据格式的操作
@Test
public void test4(){
//1. 获取连接
Jedis jedis = new Jedis("localhost",6379);
//存储sortedset
jedis.zadd("mysortedset",3,"si");
jedis.zadd("mysortedset",10,"xiao");
jedis.zadd("mysortedset",100,"xiaosi");
Set<String> mysortedset = jedis.zrange("mysortedset", 0, -1);
System.out.println(mysortedset);
jedis.close();
}
1.7Jedis连接池
对连接有更好的复用和管理
是一种自带的有连接池
@Test
public void test5(){
//创建一个配置对象
JedisPoolConfig config = new JedisPoolConfig();
//设置最大连接数
config.setMaxTotal(50);
//设置最大的空闲连接
config.setMaxIdle(10);
//创建一个连接池对象
JedisPool jedisPool = new JedisPool(config,"localhost",6379);
//获取连接
Jedis jedis = jedisPool.getResource();
//使用
jedis.set("name","xiaosi");
String name = jedis.get("name");
System.out.println(name);
}
一些常见的配置
我们为了更方便的操作,可以写一个JedisPoolUtils的工具类,用来加载properties配置文件
- JedisPoolUtils工具类
package henu.soft.xiaosi.utils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class JedisPoolUtils {
private static JedisPool jedisPool;
//通过类加载器读取配置文件
//写在静态代码块中自动执行
static{
//加载配置文件进内存
InputStream is = JedisPoolUtils.class.getClassLoader().getResourceAsStream("jedis.properties");
Properties pro = new Properties();
//关联文件
try {
pro.load(is);
} catch (IOException e) {
e.printStackTrace();
}
//获取数据,设置到JedisPoolConfig中
JedisPoolConfig config = new JedisPoolConfig();
//设置参数
config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle")));
//初始化JedisPool类变量
jedisPool = new JedisPool(config,pro.getProperty("host"),Integer.parseInt(pro.getProperty("port")));
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
- 执行测试代码
@Test
public void test6(){
//通过连接池工具类获取
Jedis jedis = JedisPoolUtils.getJedis();
//操作数据库
jedis.set("user","xiaosi");
jedis.close();
}
}
1.8案例
- 环境搭建
- 部分代码
还没用到redis
- ProvinceServlet
package henu.soft.xiaosi.web.servlet;
import com.fasterxml.jackson.databind.ObjectMapper;
import henu.soft.xiaosi.domain.Province;
import henu.soft.xiaosi.service.ProvinceService;
import henu.soft.xiaosi.service.impl.ProvinceServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet("/provinceServlet")
public class ProvinceServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 调用ServiceImpl对象查询
ProvinceService service = new ProvinceServiceImpl();
List<Province> list = service.findAll();
//2. 序列化list为json
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(list);
System.out.println(json);
//3. 响应结果
//设置响应格式
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(json);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
- ProvinceDaoImpl
package henu.soft.xiaosi.dao.impl;
import henu.soft.xiaosi.dao.ProvinceDao;
import henu.soft.xiaosi.domain.Province;
import henu.soft.xiaosi.util.JDBCUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.sql.PreparedStatement;
import java.util.List;
public class ProvinceDaoImpl implements ProvinceDao {
//声明一个成员变量 jdbcTemplate,数据库连接池对象
private JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource());
@Override
public List<Province> findAll() {
//定义sql
String sql = "select * from province";
//执行,查询的结果封装成list集合返回
List<Province> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Province>(Province.class));
return list;
}
}
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/jquery-3.3.1.js"></script>
<script>
$(function () {
//发送ajax请求,加载所有的省份数据
$.get("provinceServlet",{},function (data) {
//json格式 [{"id":1,"name":"北京"},{"id":2,"name":"上海"},{"id":3,"name":"广州"},{"id":4,"name":"陕西"}]
//获取select
var province = $("#province");
$(data).each(function () {
//遍历json数组
// 拼接数据创建option
var option = "<option name='"+ this.id+"'>" + this.name+ "</option>"
//调用select的append追加option
province.append(option);
});
})
})
</script>
</head>
<body>
<select id="province">
<option>...请选择省份...</option>
</select>
</body>
</html>
- redis缓存优化
注意:
- 使用redis缓存一些不经常发生变化的数据
- 数据库一旦执行增删改的相关操作,需要将redis缓存数据清空,再次存入
- 在service对应的增删改方法中将redis缓存删除
优化过得部分代码
- ProvinceDaoImpl
package henu.soft.xiaosi.dao.impl;
import henu.soft.xiaosi.dao.ProvinceDao;
import henu.soft.xiaosi.domain.Province;
import henu.soft.xiaosi.util.JDBCUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.sql.PreparedStatement;
import java.util.List;
public class ProvinceDaoImpl implements ProvinceDao {
//声明一个成员变量 jdbcTemplate,数据库连接池对象
private JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource());
@Override
public List<Province> findAll() {
//定义sql
String sql = "select * from province";
//执行,查询的结果封装成list集合返回
List<Province> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Province>(Province.class));
return list;
}
}
- ProvinceServiceImpl
package henu.soft.xiaosi.service.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import henu.soft.xiaosi.dao.ProvinceDao;
import henu.soft.xiaosi.dao.impl.ProvinceDaoImpl;
import henu.soft.xiaosi.domain.Province;
import henu.soft.xiaosi.jedis.JedisPoolUtils;
import henu.soft.xiaosi.service.ProvinceService;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.List;
public class ProvinceServiceImpl implements ProvinceService {
private ProvinceDao dao = new ProvinceDaoImpl();
@Override
public List<Province> findAll() {
return dao.findAll();
}
/**
* 使用redis缓存
* @return
*/
@Override
public String findAllJson() {
//1. 先从redis中查询数据
//获取redis客户端连接
Jedis jedis = JedisPoolUtils.getJedis();
String province_json = jedis.get("province");
//判断数据是否存在
if(province_json == null || province_json.length() == 0){
//redis无数据没有数据,查询数据库
System.out.println("redis无数据没有数据,查询数据库.");
List<Province> ps = dao.findAll();
//list序列化为json
ObjectMapper mapper = new ObjectMapper();
try {
province_json = mapper.writeValueAsString(ps);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
//将json数据存入redis中
jedis.set("province",province_json);
//归还连接
jedis.close();
}
else{
System.out.println("redis有数据,查询缓存。");
}
return province_json;
}
}
- ProvinceServlet
package henu.soft.xiaosi.web.servlet;
import com.fasterxml.jackson.databind.ObjectMapper;
import henu.soft.xiaosi.domain.Province;
import henu.soft.xiaosi.service.ProvinceService;
import henu.soft.xiaosi.service.impl.ProvinceServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet("/provinceServlet")
public class ProvinceServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
//1. 调用ServiceImpl对象查询
ProvinceService service = new ProvinceServiceImpl();
List<Province> list = service.findAll();
//2. 序列化list为json
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(list);
*/
//使用redis缓存优化
//调用service查询(新的查询方法)
ProvinceService service = new ProvinceServiceImpl();
String json = service.findAllJson();
System.out.println(json);
//3. 响应结果
//设置响应格式
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(json);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
二、Maven
2.1概述
是一个项目管理工具,包含
- 项目对象模型POM(Project Object Model)
- 一组标准集合
- 一个项目生命周期
- 一个依赖管理系统
- 用来运行 定义在生命周期阶段中 目标 的逻辑
2.2优势
项目开发不仅仅是写代码,其中伴随必不可少的事情,使用Maven可以帮助开发者
- 帮助开发者导入jar包:大工程引入jar包的数量很多,而且常常遇到让人抓狂的jar包冲突,版本冲突
- 帮助开发者编译Java代码
- 帮助开发者快速一次性的执行单元测试查找bug
- 帮助开发者打包完成的项目
- …
另外
- 依赖管理:Maven工程对jar包的管理工程
使用Maven开发的项目占更小的内存(一般开发的项目会因jar包的导入而占据很大的空间),Maven有一个jar包仓库,项目中只需存放jar包的坐标(pom.xml配置文件中),可多个项目共用此仓库,从而大大节省磁盘空间 - 一键构建:之前的项目环境的部署、编译、测试、运行、打包、安装、部署等一系列过程都是对项目的构建
我们不在使用本地的tomcat,而是使用Maven集成的tomcat插件来完成这些操作的过程 - …
2.3Maven安装
下载地址:http://maven.apache.org/download.cgi
下载之后解压到自定义目录,最好不要有中文名和特殊字符
- Maven目录简介:
- 配置环境变量
确保环境变量需要有JAVA_HOME
2.4Maven仓库的种类及关系
- 本地仓库
- 远程仓库
- 中央仓库
当启动一个Maven工程时,Maven会根据配置文件中的jar包坐标去找jar包
刚安装Maven的时候,本地仓库是没有jar包的,联网的情况下会自动到中央仓库下载jar包
那么多jar包有的用不到,而且有时需要在不联网的情况下进行开发,因此需要一个:
远程仓库(私服)
在公司同一局域网内,我们可以直接从远程仓库获取jar包,远程仓库如果没有可以从中央仓库获取
当然,本地仓库也能上传jar包到远程仓库
指定本地仓库的路径
2.5Maven标准目录结构
项目代码大致分为4部分
2.6常用命令
先进入到项目目录,打开命令窗口,然后执行:
-
mvn clean
:删掉target目录,也就是删除之前本地编译的所有信息,每个人的开发环境可能不相同 -
mvn compile
:编译target目录重新出现,在classes目录下生成对应包路径的.class字节码文件 -
mvn test
:除了编译正式classes文件目录,又生成一个test-classes目录,对应着项目src下的test测试代码, mvn package
:打包,target目录再次生成,编译生成classes和test-classes,生成一个新的war包
在该项目的pom.xml配置文件中默认指定打包格式为war包-
mvn install
:编译正式、测试代码,而且也打了一个包,同时把这个包安装到了本地仓库
自行测试
2.7Maven生命周期
一键构建功能,使用集成的tomcat对项目构建,步骤:编译、测试、打包、安装、发布
发布 mvn deploy
是需要进行一些配置才能执行
如果某些项目之前在其他电脑上完成部分编译等操作,我们必须执行mvn clean
命令清除项目编译信息
5个命令之间有一定的关系,执行后边的命令会把前面的命令自动执行
这5个命令被称为 默认生命周期
- 清理生命周期
- 默认生命周期
- 站点生命周期
2.8Maven概念模型图
- 项目对象模型POM(对应的pom.xml)
pom.xml中有三类信息:
- 项目自身的信息、
- 项目运行所依赖jar包信息、
- 项目运行环境信息
- 依赖管理模型
项目运行所依赖jar包信息 独立出来,形成一个 依赖管理模型
放置的全都是jar包的坐标,任何一个坐标都必须有这3个基本的元组成
依赖管理模型 指向三个仓库:
- local:本地仓库
- b2b:私服
- center:中心仓库
项目对象模型、依赖管理模型 就是 Maven 依赖管理 功能是实现
执行的命令底层就是Maven一个个的插件,对应着 Maven一键构建
2.9IEDA集成Maven插件
本地需要先安装Maven环境,然后在IDEA配置
配置步骤图解
根据settings文件自动确定本地仓库
2.10使用骨架创建Maven的Java工程
2.11不使用骨架创建Maven的Java工程
建议不使用模板,也可以直接创建一个符合Maven规则的项目
2.13使用骨架创建Maven的JavaWeb工程
小案例:完成Servlet的跳转
开始本地仓库没有jar包,可以去中央仓库去下载,需要填写jar包的下标
可以去Maven的中央仓库获取jar包坐标信息
- MyServlet
项目运行
使用插件执行 mvn tomcat:run
发现报了一个错
报错1:
org.apache.jasper.JasperException: Unable to compile class for JSP:
研究了半天,开始以为是jar包冲突造成的,修改了pom.xml配置文件中Servlet、JSP的jar包作用域为 编译阶段
结果还是报错!最后研究发现
是JDK、本地Tomcat的版本和Maven中集成的tomcat启动插件 不兼容造成的
我得JDK是11,Tomcat是8.5.3,Maven中集成的tomcat启动插件是6,不支持高版本,导致 无法编译JSP的类
解决
需要使用一个Tomcat7的插件,然后mvn tomcat7:run
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
</plugin>
终于成功!!
报错2:
如果出现下述错误,就是jar冲突造成的:
- 本地tomcat中有Servlet、JSP的jar包
- 我们在pom.xml又获取了一次
解决:
设置pom.xml中的Servlet、JSP插件仅作用于编译阶段
2.14Maven工程运行环境的修改
- 见上面tomcat7插件的使用
- 添加动态tomcat7模板,快速使用插件(代码自动补全)
- JDK插件
File—>Settings—>搜索live---->创建动态模板
设置JDK插件,可以指定JDK的版本来编译文件,同样可以定制一个模板
2.15Maven的Java工程操作数据库
获取user表中部分数据
创建User类
导入JDBCTemplate等jar包
这里的jar包驱动需要和本地数据库的版本号对应,否则可能出现错误
- UserDaoImpl
package henu.soft.dao.impl;
import henu.soft.dao.UserDao;
import henu.soft.domain.User;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class UserDaoImpl implements UserDao {
public List<User> findAll() throws SQLException, ClassNotFoundException {
//把数据库结果集转化为list集合
List<User> userList = new ArrayList<User>();
Connection connection = null;
PreparedStatement pst = null;
ResultSet rs = null;
try{
//加载驱动类进内存
Class.forName("com.mysql.jdbc.Driver");
//获取Connection对象
connection= DriverManager.getConnection("jdbc:mysql:///javaweb","root","720720");
//获得操作数据库的对象
String sql = "select * from user";
pst = connection.prepareCall(sql);
//执行数据库查询操作
rs = pst.executeQuery();
//遍历数据库结果集
while(rs.next()){
User user = new User();
user.setId(rs.getInt("id"));
user.setName((rs.getString("name")));
userList.add(user);
}
}catch (Exception e){
e.printStackTrace();
}
finally {
connection.close();
pst.close();
rs.close();
}
return userList;
}
}
- UserTest
package henu.soft.test;
import henu.soft.dao.UserDao;
import henu.soft.dao.impl.UserDaoImpl;
import henu.soft.domain.User;
import org.junit.Test;
import java.sql.SQLException;
import java.util.List;
public class UserTest {
@Test
public void findAll() throws SQLException, ClassNotFoundException {
UserDao dao = new UserDaoImpl();
List<User> userList = dao.findAll();
for (User user : userList) {
System.out.println(user);
}
}
}