博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JNDI+springmvc使用
阅读量:4302 次
发布时间:2019-05-27

本文共 13717 字,大约阅读时间需要 45 分钟。

1.JNDI简介

1-1是什么

JNDI是Java命名与目录接口(Java Naming and Directory Interface),在J2EE规范中是重要的规范之一。是一个应用程序设计的API,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口,类似JDBC都是构建在抽象层上。

JNDI可访问的现有的目录及服务有:

  • DNS
  • XNam
  • Novell目录服务
  • LDAP(Lightweight Directory Access Protocol轻型目录访问协议)
  • CORBA对象服务
  • 文件系统、Windows XP/2000/NT/Me/9x的注册表
  • RMI、DSML v1&v2、NIS 等

1-2.组件

  • Javax.naming:包含了访问命名服务的类和接口。

例如,它定义了Context接口,这是命名服务执行查询的入口。

  • Javax.naming.directory:对命名包的扩充,提供了访问目录服务的类和接口。

例如,它为属性增加了新的类,提供了表示目录上下文的DirContext接口,定义了检查和更新目录对象的属性的方法。

  • Javax.naming.event:提供了对访问命名和目录服务时的事件通知的支持。

例如,定义了NamingEvent类,这个类用来表示命名/目录服务产生的事件,定义了侦听NamingEvents的NamingListener接口。

  • Javax.naming.ldap:这个包提供了对LDAP版本3扩充的操作和控制的支持,通用包javax.naming.directory没有包含这些操作和控制。
  • Javax.naming.spi:这个包提供了一个方法,通过javax.naming和有关包动态增加对访问命名和目录服务的支持。这个包是为有兴趣创建服务提供者的开发者提供的。

1-3.源码

关键代码都贴出来了,不看源码也可以。

2.JDBC驱动

步骤:

  • 加载数据库驱动程序 Class.forName("数据库驱动类");
  • 连接数据库 Connection con = DriverManager.getConnection();
  • 操作数据库 PreparedStatement stat = con.prepareStatement(sql);stat.executeQuery();
  • 关闭数据库,释放连接 con.close();

本篇文件用到的数据库表和数据,请参照 里,进行建表和插入数据

依赖

mysql
mysql-connector-java
8.0.15

实体类

public class Emp {
private long empno; private String ename; private String job; private long mgr; private Date hiredate; private double sal; private double comm; private long deptno; ...省略setter、getter、toString...}

MySQLDemo

public class MySQLDemo {
private static final String DRIVER_NAME = "com.mysql.cj.jdbc.Driver"; // private static final String DRIVER_NAME = "com.mysql.jdbc.Driver"; private static final String JDBC_URL = "jdbc:mysql://localhost:3306"; private static final String USER = "iworkh"; private static final String PASSWORD = "iworkh123"; public static void main(String[] args) {
Connection conn = null; try {
Class.forName(DRIVER_NAME); conn = DriverManager.getConnection(JDBC_URL, USER, PASSWORD); String sql= "select * from iworkh_demo.emp where ename like ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1,"%M%"); ResultSet resultSet = ps.executeQuery(); while (resultSet.next()){
Emp emp = new Emp(); emp.setEmpno(resultSet.getLong("empno")); emp.setEname(resultSet.getString("ename")); emp.setJob(resultSet.getString("job")); emp.setMgr(resultSet.getLong("mgr")); emp.setHiredate( resultSet.getDate("hiredate")); emp.setSal(resultSet.getDouble("sal")); emp.setComm(resultSet.getDouble("comm")); emp.setDeptno(resultSet.getLong("deptno")); System.out.println(emp); } } catch (ClassNotFoundException | SQLException e) {
e.printStackTrace(); } finally {
if (conn != null) {
try {
conn.close(); } catch (SQLException throwables) {
throwables.printStackTrace(); } } } }}

这种做法存在的问题:

  • 数据库服务器名称MyDBServer 、用户名和口令都可能需要改变,由此引发JDBC URL需要修改;
  • 数据库可能改用别的产品,如改用DB2或者Oracle,引发JDBC驱动程序包和类名需要修改;
  • 随着实际使用终端的增加,原配置的连接池参数可能需要调整;

代码应该不需要关心

  • 具体的数据库后台是什么?
  • JDBC驱动程序是什么?
  • JDBC URL格式是什么?
  • 访问数据库的用户名和口令是什么?

程序应该没有对 JDBC 驱动程序的引用,没有服务器名称,没有用户名称或口令

甚至没有数据库池或连接管理。而是把这些问题交给J2EE容器来配置和管理,只需要对这些配置和管理进行引用即可。

3.springmvc+JDNI形式

代码结构

下面使用了spring、springmvc等知识,如果不足的可以通过下面提供的链接,自己补充下。

3-1.依赖

war

项目打包指定为war

org.springframework
spring-web
org.springframework
spring-webmvc
mysql
mysql-connector-java
com.fasterxml.jackson.core
jackson-core
2.11.0
com.fasterxml.jackson.core
jackson-databind
2.11.0
com.fasterxml.jackson.core
jackson-annotations
2.11.0

引入springmvc依赖、mysql驱动、jackson依赖

3-2.web.xml

文件路径:src/main/webapp/WEB-INF/web.xml

Archetype Created Web Application
contextConfigLocation
classpath*:spring-bean.xml
org.springframework.web.context.ContextLoaderListener
encodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
encodingFilter
/*
dispatcherServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath*:spring-mvc.xml
dispatcherServlet
/

3-3.context.xml

文件路径:src/main/webapp/WEB-INF/context.xml

  • factory:该Resource 配置使用的是哪个数据源配置类,这里使用的是tomcat自带的标准数据源Resource配置类,这个类也可以自己写,实现javax.naming.spi.ObjectFactory 接口即可。

如果使用其他的数据池,如阿里巴巴的druid,要满足两个条件:

  • 其实现了javax.naming.spi.ObjectFactory,druid的com.alibaba.druid.pool.DruidDataSourceFactory就实现了
  • 需把jar及其依赖的jar包 ,都放在tomcat的lib下,光放在工程的WEB-INF/lib下是不够的。阿里巴巴的druid依赖log4j,所以后者的jar也要复制进去
  • driverClassName
  • msyql: com.mysql.cj.jdbc.Driver
  • oracle:oracle.jdbc.driver.OracleDriver
  • db2:com.ibm.db2.jcc.DB2Driver
  • SQLServer:com.microsoft.sqlserver.jdbc.SQLServerDriver
  • url的其他写法示例
  • mysql: jdbc:mysql://localhost:3306/iworkh_demo
  • oracle:jdbc:oracle:thin:@192.168.1.249:1521:XE
  • db2:jdbc:db2://18.1.99.7:55555/esdb:currentSchema=EMPSAL

配置方法有多种,这使用conf/context.xml改配置

注意

需要将context.xml文件复制到tomcat的安装目录的conf下(对context.xml文件修改、覆盖都行)。

其他方式有兴趣可以阅读下面几篇文章

3-4.spring配置文件

文件路径:src/main/resources/spring-mvc.xml

文件路径:src/main/resources/spring-bean.xml

方式一

方式二

JNDI地址有两种写法

  • java:comp/env/jdbc/iworkh_demo_read
  • jdbc/iworkh_demo_read

在J2EE中的引用常用的有:

  • JDBC 数据源引用在java:comp/env/jdbc 子上下文中声明
  • JMS 连接工厂在java:comp/env/jms 子上下文中声明
  • JavaMail 连接工厂在java:comp/env/mail 子上下文中声明
  • URL 连接工厂在 java:comp/env/url 子上下文中声明

3-5.代码

Emp的实体类

public class Emp {
private long empno; private String ename; private String job; private long mgr; private Date hiredate; private double sal; private double comm; private long deptno; ...省略setter、getter、toString方法...}

Emp的dao

@Repositorypublic class JndiEmpDao {
@Autowired private DataSource iworkhDemoRead; public List
list() {
Connection conn = null; try {
conn = iworkhDemoRead.getConnection(); String sql = "select * from iworkh_demo.emp where ename like ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, "%M%"); ResultSet resultSet = ps.executeQuery(); List
empList = new LinkedList<>(); while (resultSet.next()) {
Emp emp = new Emp(); emp.setEmpno(resultSet.getLong("empno")); emp.setEname(resultSet.getString("ename")); emp.setJob(resultSet.getString("job")); emp.setMgr(resultSet.getLong("mgr")); emp.setHiredate(resultSet.getDate("hiredate")); emp.setSal(resultSet.getDouble("sal")); emp.setComm(resultSet.getDouble("comm")); emp.setDeptno(resultSet.getLong("deptno")); empList.add(emp); } return empList; } catch (SQLException e) {
e.printStackTrace(); } finally {
if (conn != null) {
try {
conn.close(); } catch (SQLException throwables) {
throwables.printStackTrace(); } } } return null; }}

Emp的service

@Servicepublic class JndiEmpService {
@Autowired private JndiEmpDao jndiEmpDao; public List
list() {
return jndiEmpDao.list(); }}

Emp的controller

@RestController@RequestMapping("/emp")public class JndiEmpController {
@Autowired private JndiEmpService jndiDemoService; @GetMapping("/list") public List
list() {
return jndiDemoService.list(); }}

测试controller

@RestController@RequestMapping("/")public class IndexController {
@GetMapping("/") public String index() {
return "hello,world"; } @GetMapping("/data") public List
data(){
List
data = new ArrayList<>(); data.add("111"); data.add("222"); return data; }}

3-6.测试

  • http://localhost:8080/
  • http://localhost:8080/data
  • http://localhost:8080/jndi-web/emp/list

示例结果

[    {
"empno": 7369, "ename": "SMITH", "job": "CLERK", "mgr": 7902, "hiredate": 345830400000, "sal": 800, "comm": 0, "deptno": 20 }, {
...省略其他... }]

4.读写分离库

4-1.sql

建库

CREATE DATABASE IF NOT EXISTS iworkh_demo    DEFAULT CHARACTER SET utf8mb4    DEFAULT COLLATE utf8mb4_general_ci;

建表

create table t_order(    id int unsigned auto_increment primary key COMMENT 'id',    product_name  varchar(100) COMMENT '产品名',    count    int(50) COMMENT '数量', 		price    decimal(7, 2) COMMENT '单价') ENGINE = InnoDB  DEFAULT CHARSET = utf8mb4 COMMENT ='订单表';

4-2.配置

文件位置:src/main/webapp/WEB-INF/context.xml

WEB-INF/web.xml
${catalina.base}/conf/web.xml

为了简单起见,写和读的库都使用一样。这配置完全可以使用不一样的。一个库为写库,一个库为读库。

文件位置:src/main/webapp/WEB-INF/context.xml

4-3.代码

实体类

public class Order {
private int id; private String productName; private int count; private double price; ...省略setter、getter、toString方法...}

dao

@Repositorypublic class OrderDao extends BaseDao {
public void add(Order order) {
Connection conn = null; try {
System.out.println("add---" + iworkhOrderWrite.hashCode()); conn = iworkhOrderWrite.getConnection(); String sql = "insert into t_order (`product_name`, `count`, `price`) values (?, ?, ?)"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, order.getProductName()); ps.setInt(2, order.getCount()); ps.setDouble(3, order.getPrice()); ps.executeUpdate(); } catch (SQLException throwables) {
throwables.printStackTrace(); } finally {
if (conn != null) {
try {
conn.close(); } catch (SQLException throwables) {
throwables.printStackTrace(); } } } } public List
list() {
Connection conn = null; try {
System.out.println("list---" + iworkhOrderRead.hashCode()); conn = iworkhOrderRead.getConnection(); String sql = "select * from t_order"; PreparedStatement ps = conn.prepareStatement(sql); ResultSet resultSet = ps.executeQuery(); List
orderList = new LinkedList<>(); while (resultSet.next()) {
Order order = new Order(); order.setId(resultSet.getInt("id")); order.setProductName(resultSet.getString("product_name")); order.setCount(resultSet.getInt("count")); order.setPrice(resultSet.getDouble("price")); orderList.add(order); } return orderList; } catch (SQLException throwables) {
throwables.printStackTrace(); } finally {
if (conn != null) {
try {
conn.close(); } catch (SQLException throwables) {
throwables.printStackTrace(); } } } return null; }}

service

@Servicepublic class OrderService {
@Autowired private OrderDao orderDao; public void add(Order order) {
orderDao.add(order); } public List
list() {
return orderDao.list(); }}

controller

@RestController@RequestMapping("/order")public class OrderController {
@Autowired private OrderService orderService; @GetMapping("/add") public void add() {
Order order = new Order(); order.setProductName("dell显示器"); order.setCount(1); order.setPrice(2100.00); orderService.add(order); } @GetMapping("/list") public List
list() {
return orderService.list(); }}

4-4.测试

  • http://localhost:8080/
  • http://localhost:8080/data
  • http://localhost:8080/jndi-web/emp/list
  • http://localhost:8080/jndi-web/order/add
  • http://localhost:8080/jndi-web/order/list

查看order里的add和list方法的hash code是不一样的。即达到了读写分离的效果。

5.分库分表中间件

分表内容有点多,直接另写一篇文章。请参照下篇文章

6.扩展链接

能读到文章最后,首先得谢谢您对本文的肯定,你的肯定是对博主最大的鼓励。

你觉本文有帮助,那就点个👍

你有疑问,那就留下您的💬
怕把我弄丢了,那就把我⭐
电脑不方便看,那就把发到你📲

转载地址:http://ikhws.baihongyu.com/

你可能感兴趣的文章
FFmpeg 的介绍与使用
查看>>
Android 虚拟机简单介绍——ART、Dalvik、启动流程分析
查看>>
原理性地理解 Java 泛型中的 extends、super 及 Kotlin 的协变、逆变
查看>>
FFmpeg 是如何实现多态的?
查看>>
FFmpeg 源码分析 - avcodec_send_packet 和 avcodec_receive_frame
查看>>
FFmpeg 新旧版本编码 API 的区别
查看>>
RecyclerView 源码深入解析——绘制流程、缓存机制、动画等
查看>>
Android 面试题整理总结(一)Java 基础
查看>>
Android 面试题整理总结(二)Java 集合
查看>>
学习笔记_vnpy实战培训day02
查看>>
学习笔记_vnpy实战培训day03
查看>>
VNPY- VnTrader基本使用
查看>>
VNPY - CTA策略模块策略开发
查看>>
VNPY - 事件引擎
查看>>
MongoDB基本语法和操作入门
查看>>
学习笔记_vnpy实战培训day04_作业
查看>>
OCO订单(委托)
查看>>
学习笔记_vnpy实战培训day05
查看>>
学习笔记_vnpy实战培训day06
查看>>
Python super钻石继承
查看>>