图书管理系统【用户、购买、订单模块、添加权限】

数据库课程设计实验报告--图书管理系统 数据库课设图书管理系统 目录 一、系统背景 二、需求分析 (一)系统综合需求 (二)系统逻辑模型 三、系统设计 (一)概念结构设计 (二) 逻辑结构设计 (三)子模块划分及功能概述 四、详细设计 (一)开发平台及工具 (二)存储过程及触发器 (三)应用程序设计 (四)用户界面设计 五、课程设计总结 六、参考文献 七、附录 一.系统背景 图书馆信息管理系统数据库用以收集、存储书籍信息、人员(读者、图书管理员)信息、图书借阅信息以及意外处理信息,及时记录存储各个环节信息的变更,以便管理、查询、显示、输出, 阅读详情

用户模块

要登陆后才能购买,因此我们先写购买模块.

设计实体


    private String id;
    private String username;
    private String password;
    private String email;
    private String cellphone;
    private String address;

    //各种setter、getter

设计数据库表


CREATE TABLE user (

  id        VARCHAR(40) PRIMARY KEY,
  username  VARCHAR(20) NOT NULL,
  cellphone VARCHAR(20) NOT NULL,
  address   VARCHAR(40) NOT NULL,
  email     VARCHAR(30),
  password  VARCHAR(30) NOT NULL

);

编写DAO


/**
 * 用户的登录注册模块
 * 1:登陆
 * 2:注册
 * 3:根据id查找具体的用户
 */
public class UserDaoImpl {



    public void register(User user) {

        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        String sql = "INSERT INTO user (id,username,cellphone,address,email,password) VALUES(?,?,?,?,?,?)";
        try {

            queryRunner.update(sql, new Object[]{user.getId(),user.getUsername(), user.getCellphone(), user.getAddress(), user.getEmail(), user.getPassword()});
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public User login(String username, String password) {

        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        String sql = "SELECT * FROM user WHERE username = ? AND password=?";
        try {

            return (User) queryRunner.query(sql, new Object[]{username, password}, new BeanHandler(User.class));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public User find(String id) {

        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        String sql = "SELECT * FROM user WHERE id=?";
        try {

            return (User) queryRunner.query(sql, id, new BeanHandler(User.class));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

}

测试DAO


public class UserDemo {
    UserDaoImpl userDao = new UserDaoImpl();

    @Test
    public void add() {

        User user = new User();
        user.setId("1");
        user.setUsername("zhong");
        user.setPassword("123");
        user.setCellphone("10085");
        user.setAddress("广州萝岗");
        user.setEmail("40368324234234@QQ.com");

        userDao.register(user);
    }

    @Test
    public void find() {

        String id = "1";
        User user = userDao.find(id);

        System.out.println(user.getEmail());
    }

    @Test
    public void login() {
        String username = "zhong";
        String password = "123";
        User user = userDao.login(username, password);

        System.out.println(user.getAddress());
    }
}

抽取DAO


public interface UserDao {
    void register(User user);

    User login(String username, String password);

    User find(String id);
}

编写Service


    private UserDao userDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.UserDaoImpl", UserDao.class);

    public void registerUser(User user) {
        userDao.register(user);
    }

    public User loginUser(String username,String password) {
        return userDao.login(username, password);
    }

    public User findUser(String id) {
        return userDao.find(id);
    }

前台样式

  • head.jsp

<div id="User">
    用户名:<input type="text" name="username">
    密码:<input type="password" name="password">
    <button name="login">登陆</button>
    <button name="register">注册</button>
</div>
  • head.css

#body {
    position: relative;
}
#user {
    position: absolute;
    margin-top: 130px;
    margin-left: 1364px;
}
  • 效果:

这里写图片描述


实现登陆注册功能

当点击登陆按钮的时候,把数据带过去给Servlet,让Servlet调用BusinessService方法,实现登陆。注册同理…..因此,我们需要用到JavaScript代码

  • head.jsp

<c:if test="${user==null}" >
<div id="User">
    用户名:<input type="text" id="username">
    密码:<input type="password" id="password">
    <button name="login" onclick="login()">登陆</button>
    <button name="register" onclick="register()">注册</button>
</div>
</c:if>

<c:if test="${user!=null}" >
    <div id="User">
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎您:${user.username}&nbsp;&nbsp;&nbsp;&nbsp;<a href="${pageContext.request.contextPath}/UserServlet?method=Logout">注销</a>
    </div>
</c:if>
  • javaScript代码

    <script type="text/javascript">

        function login() {
            //得到输入框的数据
            var username = document.getElementById("username").value;
            var password = document.getElementById("password").value;

            //跳转到相对应的Servlet上
            window.location.href = "${pageContext.request.contextPath}/UserServlet?method=login&username=" + username + "&password=" + password;
        }

        function register() {

            //跳转到注册页面
            window.location.href = "${pageContext.request.contextPath}/client/register.jsp";
        }
    </script>
  • UserServlet


        String method = request.getParameter("method");

        BussinessServiceImpl service = new BussinessServiceImpl();
        if (method.equals("login")) {

            try {
                //得到页面传递过来的数据
                String username = request.getParameter("username");
                String password = request.getParameter("password");
                User user = service.loginUser(username, password);

                request.getSession().setAttribute("user",user);
                request.getRequestDispatcher("/client/head.jsp").forward(request, response);

            } catch (Exception e) {
                request.setAttribute("message", "登陆失败了!");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
            }

        } else if (method.equals("register")) {

            try {
                //得到JSP传递过来的数据,封装成Bean对象
                User user = WebUtils.request2Bean(request, User.class);
                user.setId(WebUtils.makeId());

                service.registerUser(user);

                request.setAttribute("message", "注册成功了!");

            } catch (Exception e) {
                e.printStackTrace();
                request.setAttribute("message", "注册失败了!");
            }
            request.getRequestDispatcher("/message.jsp").forward(request, response);
        } else if (method.equals("Logout")) {

            //销毁session
            request.getSession().invalidate();

            //回到首页
            request.getRequestDispatcher("/client/head.jsp").forward(request, response);

        }

购买模块

在显示图书的时候,顺便添加购买的超链接

    <li><a href="#">购买</a></li>

设计购物车实体

如果不清楚为什么这样设计,可参考我之前的博文:http://blog.youkuaiyun.com/hon_3y/article/details/56481439#t5

  • Cart实体

public class Cart {

    private Map<String, CartItem> map = new HashMap<>();
    private double price;


    //提供把商品添加到购物的功能
    public void addBook2Cart(Book book) {

        //得到对应的购物项
        CartItem cartItem = map.get(book.getId());

        //如果是null,说明购物车还没有该购物项
        if (cartItem == null) {
            cartItem = new CartItem();
            cartItem.setQuantity(1);
            cartItem.setBook(book);
            cartItem.setPrice(book.getPrice());

            //把购物项加到购物车中
            map.put(book.getId(), cartItem);
        } else {

            //如果购物车有该购物项了,那么将购物项的数量+1
            cartItem.setQuantity(cartItem.getQuantity() + 1);
        }
    }


    //购物车的价钱是购物项价钱的总和
    public double getPrice() {

        double totalPrice = 0;
        for (Map.Entry<String, CartItem> me : map.entrySet()) {
            CartItem cartItem = me.getValue();
            totalPrice += cartItem.getPrice();
        }

        return totalPrice;
    }

    public Map<String, CartItem> getMap() {
        return map;
    }

    public void setMap(Map<String, CartItem> map) {
        this.map = map;
    }


    public void setPrice(double price) {
        this.price = price;
    }
}

设计购物项实体


public class CartItem {

    private Book book;
    private double price;
    private int quantity;

    public double getPrice() {
        return this.book.getPrice() * this.quantity;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
    }
    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }
}

处理用户想要买的书籍Servlet

    <li><a href="${pageContext.request
.contextPath}/BuyServlet?book_id=${book.id}">购买</a></li>
  • BuyServlet

        BussinessServiceImpl service = new BussinessServiceImpl();

        //先检查该用户是否登陆了。
        User user = (User) request.getSession().getAttribute("user");
        if (user == null) {
            request.setAttribute("message", "您还没登陆,请登陆了再来购买");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
            return ;
        }

        //如果登陆了...

        //得到该用户的购物车
        Cart cart = (Cart) request.getSession().getAttribute("cart");
        if (cart == null) {
            cart = new Cart();
            request.getSession().setAttribute("cart", cart);
        }

        //得到用户想买的书籍
        String book_id = request.getParameter("book_id");
        Book book = service.findBook(book_id);

        //把书籍添加到购物车中
        service.buyBook(cart, book);
        request.setAttribute("message", "该商品已添加到购物车中");
        request.getRequestDispatcher("/message.jsp").forward(request,response);

提供显示购物车商品的Servlet


        //先判断该用户是否登陆了
        User user = (User) request.getSession().getAttribute("user");
        if (user == null) {
            request.setAttribute("message", "您还没有登陆呢!");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
            return;
        }

        //如果登陆了.....
        Cart cart = (Cart) request.getSession().getAttribute("cart");

        //把该用户的购物车给JSP页面显示
        request.setAttribute("cart", cart);
        request.getRequestDispatcher("/client/listCart.jsp").forward(request, response);

显示购物车的JSP页面


<c:if test="${empty(cart.map)}">

    您还没有购买过任何商品哦!!!
</c:if>


<table border="1px">
    <c:if test="${!empty(cart.map)}">
        <h1>您购物车下有如下的商品:</h1><br>

        <tr>
            <td>书名:</td>
            <td>作者:</td>
            <td>数量:</td>
            <td>价钱:</td>
        </tr>
        <c:forEach items="${cart.map}" var="cartItme">


            <tr>
                <td>${cartItme.value.book.name}</td>
                <td>${cartItme.value.book.author}</td>
                <td>${cartItme.value.quantity}</td>
                <td>${cartItme.value.price}</td>
            </tr>
        </c:forEach>

    </c:if>
</table>

效果:

这里写图片描述


订单模块

在前台用户界面中,当用户要把购物车付款时,应该提供生成订单的超链接….

这里写图片描述


设计订单实体

订单应该包含id,收货人信息,下单的时间,订单的总价,订单的状态【有无发货】..而不应该包含商品的信息的。商品的信息用一个专门的”订单项“来表示

一个订单对应多个订单项,这是一对多的关系!

    private String id;

    //下单的时间、日期、状态
    private Date date;
    private double price;
    private boolean state;

    //一个用户可以有多个订单,把用户记住
    private String user_id;

    //一个订单中有多个订单项
    private Set<OrderItem> items = new HashSet<>();

    //各种的setter和getter

设计订单项实体


    private String id;


    //一本书对应多个订单项,订单项一定是由书组成,记住书
    private String book_id;

    private double price;
    private int quantity;

    //各种的setter和getter

设计数据库表

  • 订单表

mysql不能创建名为”order”的表,后边加个s就可以



CREATE TABLE orders (
  id      VARCHAR(40) PRIMARY KEY,
  date    DATE        NOT NULL,
  user_id VARCHAR(40) NOT NULL,
  state   BOOLEAN,
  price   DOUBLE,
  CONSTRAINT user_id_FK FOREIGN KEY (user_id) REFERENCES user (id)
);
  • 订单项表:

CREATE TABLE orderItem (
  id       VARCHAR(40) PRIMARY KEY,
  price    DOUBLE,
  quantity INT,
  order_id VARCHAR(40) ,
  book_id  VARCHAR(40) ,
  CONSTRAINT order_id_FK FOREIGN KEY (order_id) REFERENCES orders (id),
  CONSTRAINT book_id_FK FOREIGN KEY (book_id) REFERENCES book (id)
);
  • 表之间的结构:

这里写图片描述


设计Dao


public class OrderDaoImpl implements zhongfucheng.dao.OrderDao {

    @Override
    public void addOrder(Order order) {
        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
        String sql1 = "INSERT INTO orders(id,ordertime,user_id,state,price) VALUES(?,?,?,?,?)";
        try {
            //订单的基本信息
            queryRunner.update(sql1, new Object[]{order.getId(), order.getOrdertime(), order.getUser_id(), order.isState(), order.getPrice()});

            //订单项的信息
            String sql2 = "INSERT INTO orderItem(id,price,quantity,order_id,book_id) VALUES(?,?,?,?,?)";

            Set<OrderItem> items = order.getItems();

            for (OrderItem item : items) {
                queryRunner.update(sql2, new Object[]{item.getId(), item.getPrice(), item.getQuantity(), item.getOrder_id(), item.getBook_id()});
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Order findOrder(String id) {
        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        Order order;
        try {
            //找出订单的基本信息
            String sql = "SELECT * FROM orders WHERE id=?";
            order = (Order) queryRunner.query(sql, new BeanHandler(Order.class), new Object[]{id});

            //找出订单的所有订单项
            String sql2 = "SELECT * FROM orderItem WHERE order_id=?";
            List<OrderItem> list = (List<OrderItem>) queryRunner.query(sql2, new BeanListHandler(OrderItem.class), new Object[]{order.getId()});

            System.out.println("这是数据库拿到的list集合:"+list.size());


            //将所有订单项装到订单里边
            order.getItems().addAll(list);
            System.out.println("这是数据库拿到的"+order.getItems().size());


            //找出该订单是属于哪一个用户的
            String sql3 = "SELECT * FROM orders o,user u WHERE o.user_id=u.id AND o.id=? ";
            User user = (User) queryRunner.query(sql3, new BeanHandler(User.class), new Object[]{order.getId()});

            order.setUser_id(user.getId());
            return order;


        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }


    //更新订单的状态
    public void updateState(String id) {

        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        String sql = "UPDATE orders SET state=? WHERE id=?";

        try {
            queryRunner.update(sql, new Object[]{true, id});
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    //查看已经发货或没发货的订单信息
    public List<Order> getAllOrder(boolean state) {
        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        String sql = "SELECT * FROM orders WHERE state=? ";
        try {
            return (List<Order>) queryRunner.query(sql, new BeanListHandler(Order.class), new Object[]{state});
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    //通过用户的id查找用户的订单,可能不止一个
    public List<Order> findUserOrder(String user_id) {
        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        String sql = "SELECT * FROM orders WHERE user_id=? ";

        try {
            return List<Order> queryRunner.query(sql, new BeanHandler(Order.class), new Object[]{user_id});

        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

    }
}

二次更新

在编写dao的时候,尤其是Add方法。它是将所有数据都封装到Order对象上,然后取出数据,把数据插入到数据表中

  • 其实,我们的Order和OrderItem的操作可以分开。OrderItem也可以另外编写一个Dao,那么我们在插入完Order对象之后,得到Order对象返回的主键,再调用OrderItemDao的方法来插入OrderItem的数据,这样我觉得会让代码清晰一些。
  • 在OrderItemDao中接收的是一个List,因为我们一个订单会对应多个订单项。

抽取成DAO接口


public interface OrderDao {
    void addOrder(Order order);

    Order findOrder(String id);

    List<Order> getAllOrder(boolean state);

    void updateState(String user_id);

    List<Order> findUserOrder(String user_id);
}

BussinessService

    private OrderDao orderDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.OrderDaoImpl", OrderDao.class);
    public void createOrder(Cart cart, User user) {

        //订单的基本信息
        String order_id = WebUtils.makeId();
        Order order = new Order();
        order.setId(order_id);
        order.setPrice(cart.getPrice());
        order.setOrdertime(new Date());
        order.setState(false);
        order.setUser_id(user.getId());


        //订单项的基本信息
        //得到每个购物项,购物项就作为订单项
        for (Map.Entry<String, CartItem> me : cart.getMap().entrySet()) {

            OrderItem orderItem = new OrderItem();
            CartItem cartItem = me.getValue();

            orderItem.setId(WebUtils.makeId());
            orderItem.setPrice(cartItem.getPrice());
            orderItem.setBook_id(cartItem.getBook().getId());
            orderItem.setQuantity(cartItem.getQuantity());
            orderItem.setOrder_id(order_id);
            order.getItems().add(orderItem);
        }

        orderDao.addOrder(order);

    }

    public Order findOrder(String user_id) {

        return orderDao.findOrder(user_id);
    }

    public List<Order> getAllOrder(boolean state) {
        return orderDao.getAllOrder(state);
    }

    public void sendOutOrder(String id) {

        orderDao.updateState(id);
    }

    public List<Order> findUserOrder(String user_id) {
        return orderDao.findUserOrder(user_id);
    }

生成订单的Servlet



        BussinessServiceImpl service = new BussinessServiceImpl();

        //检查该用户的购物车是否有商品
        Cart cart = (Cart) request.getSession().getAttribute("cart");
        if (cart == null) {
            request.setAttribute("message", "您购物车没有商品,无法生成订单");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
            return;
        }

        //如果有商品,得到当前用户
        User user = (User) request.getSession().getAttribute("user");
        service.createOrder(cart, user);
        request.setAttribute("message", "订单已经生成了,准备好钱来收货把");
        request.getRequestDispatcher("/message.jsp").forward(request, response);
        return;

用户查询自己的订单Servlet


    <a href="${pageContext.request.contextPath}/LookOrder" target="body">查看订单</a>

        BussinessServiceImpl service = new BussinessServiceImpl();

        //检查该用户是否登陆了
        User user = (User) request.getSession().getAttribute("user");
        if (user == null) {
            request.setAttribute("message", "您还没登陆,等您登陆了再来看把");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
            return;
        }

        //用户登陆了!
        Order order = service.findUserOrder(user.getId());

        //交给相对应的JSP 显示
        request.setAttribute("order", order);
        request.setAttribute("user",user);
        request.getRequestDispatcher("/client/listOrder.jsp").forward(request, response);
        return ;

显示订单数据的JSP


<c:if test="${order==null}">
    您还没有下过任何订单!!

</c:if>

<c:if test="${order!=null}">

    <table border="1px">

        <tr>
            <td>下单人:</td>
            <td>订单时间</td>
            <td>订单状态</td>
            <td>订单价钱</td>
        </tr>
        <tr>
            <td>${user.username}</td>
            <td>${order.ordertime}</td>
            <td>${order.state==false?"未发货":"已发货"}</td>
            <td>${order.price}</td>
        </tr>

    </table>

</c:if>

效果:

这里写图片描述


后台查询订单的状况Servlet


<a href="${pageContext.request.contextPath}/OrderServlet?state=false" target="body">待处理订单</a><br>
<a href="${pageContext.request.contextPath}/OrderServlet?state=true" target="body">已发货订单</a><br>

        BussinessServiceImpl service = new BussinessServiceImpl();
        String state = request.getParameter("state");

        if (state.equals("true")) {
            List<Order> list = service.getAllOrder(true);
            request.setAttribute("list",list);

        } else if (state.equals("false")) {
            List<Order> list = service.getAllOrder(false);
            request.setAttribute("list", list);
        }


        request.getRequestDispatcher("/background/listOrder.jsp").forward(request, response);

显示订单状况的JSP


<c:if test="${empty(list)}">

    还没有任何订单哦!

</c:if>

<c:if test="${!empty(list)}">

    <table border="1px">

        <tr>
            <td>下单人:</td>
            <td>订单时间</td>
            <td>订单状态</td>
            <td>订单价钱</td>
            <td>操作</td>
        </tr>

        <c:forEach items="${list}" var="order">
            <tr>
                <td>${order.user_id}</td>
                <td>${order.ordertime}</td>
                <td>${order.state==false?"未发货":"已发货"}</td>
                <td>${order.price}</td>
                <td>
                    <a href="${pageContext.request.contextPath}/orderItemServlet?order_id=${order.id}">查看详细信息</a>
                    <a href="#">删除</a>

                </td>
            </tr>
        </c:forEach>


    </table>


</c:if>

查看具体订单的详细信息Servlet


        BussinessServiceImpl service = new BussinessServiceImpl();

        //得到用户想要查看详细信息的表单
        String order_id = request.getParameter("order_id");

        Order order = service.findOrder(order_id);

        //将该order对象给相对应的JSP显示
        request.setAttribute("order", order);
        request.getRequestDispatcher("/background/listDetail.jsp").forward(request, response);

查看具体订单的详细信息JSP


<table border="1px">

   <tr>
       <td>书籍的编号</td>
       <td>价钱</td>
       <td>数量</td>
       <td>操作</td>
   </tr>
    <c:forEach items="${order.items}" var="item">
        <tr>
            <td>${item.book_id}</td>
            <td>${item.price}</td>
            <td>${item.quantity}</td>
            <td><a href="${pageContext.request.contextPath}/SendOutServlet?id=${order.id}">发货</a></td>
        </tr>
    </c:forEach>
</table>

处理发货的Servlet



        BussinessServiceImpl service = new BussinessServiceImpl();
        String id = request.getParameter("id");

        service.sendOutOrder(id);
        request.setAttribute("message", "已发货!");
        request.getRequestDispatcher("/message.jsp").forward(request, response);
        return;

效果:

这里写图片描述


添加权限控制

目前为止,我们已经学习了动态代理技术和注解技术了。于是我们想要为之前的bookStore项目添加权限控制…..

只有用户有权限的时候,后台管理才可以进行相对应的操作…..


实现思路

这里写图片描述

之前我们做权限管理系统的时候,是根据用户请求的URI来判断该链接是否需要权限的。这次我们使用动态代理的技术和注解来判断:用户调用该方法时,检查该方法是否需要权限…

根据MVC模式,我们在web层都是调用service层来实现功能的。那么我们具体的思路是这样的:

  • web层调用service层的时候,得到的并不是ServiceDao对象,而是我们的代理对象
  • 在service层中的方法添加注解,如果方法上有注解,那么说明调用该方法需要权限…
  • 当web层调用代理对象方法的时候,代理对象会判断该方法是否需要权限,再给出相对应的提示….

设计实体、数据库表

上次我们做的权限管理系统是引入了角色这个概念的,这次主要为了练习动态代理和注解技术,就以简单为主,不引入角色这个实体。直接是用户和权限之间的关系了。

Privilege实体


public class Privilege {

    private String id ;
    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

数据库表

  • privilege表


CREATE TABLE privilege (

  id   VARCHAR(40) PRIMARY KEY,
  name VARCHAR(40)

);

privilege和user是多对多的关系,于是使用第三方表来维护他们的关系

  • user_privilege表


CREATE TABLE user_privilege (
  privilege_id VARCHAR(40),
  user_id      VARCHAR(40),

  PRIMARY KEY (privilege_id, user_id),
  CONSTRAINT privilege_id_FK FOREIGN KEY (privilege_id) REFERENCES privilege(id),
  CONSTRAINT user_id_FK1 FOREIGN KEY (user_id) REFERENCES user(id)

);


添加测试数据

为了方便,直接添加数据了。就不写详细的DAO了。

  • 在数据库中添加了两个权限

这里写图片描述

  • 为id为1的user添加了两个权限

这里写图片描述


编写DAO

后面在动态代理中,我们需要检查该用户是否有权限…那么就必须查找出该用户拥有的哪些权限。再看看用户有没有相对应的权限

    //查找用户的所有权限
    public List<Privilege> findUserPrivilege(String user_id) {
        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        String sql = "SELECT p.* FROM privilege p, user_privilege up WHERE p.id = up.privilege_id AND up.user_id = ?";
        try {
            return (List<Privilege>) queryRunner.query(sql, new Object[]{user_id}, new BeanListHandler(Privilege.class));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

抽取到接口上


    List<Privilege> findUserPrivilege(String user_id);

注解模块

  • 编写注解
@Retention(RetentionPolicy.RUNTIME)
public @interface permission {
    String value();
}
  • 在Service层方法中需要权限的地方添加注解CategoryServiceImpl

    @permission("添加分类")
    /*添加分类*/
    public void addCategory(Category category) {
        categoryDao.addCategory(category);
    }


    /*查找分类*/
    public void findCategory(String id) {
        categoryDao.findCategory(id);
    }

    @permission("查找分类")
    /*查看分类*/
    public List<Category> getAllCategory() {
        return categoryDao.getAllCategory();
    }

抽取Service

把Service的方法抽取成ServiceDao。在Servlet中,也是通过ServiceFactory来得到Service的对象【和DaoFactory是类似的】

CategoryService


    @permission("添加分类")
    /*添加分类*/ void addCategory(Category category);

    /*查找分类*/
    void findCategory(String id);

    @permission("查找分类")
    /*查看分类*/ List<Category> getAllCategory();

ServiceFactory


public class ServiceDaoFactory {

    private static final ServiceDaoFactory factory = new ServiceDaoFactory();

    private ServiceDaoFactory() {
    }

    public static ServiceDaoFactory getInstance() {
        return factory;
    }


    //需要判断该用户是否有权限
    public <T> T createDao(String className, Class<T> clazz, final User user) {

        System.out.println("添加分类进来了!");

        try {
            //得到该类的类型
            final T t = (T) Class.forName(className).newInstance();
            //返回一个动态代理对象出去
            return (T) Proxy.newProxyInstance(ServiceDaoFactory.class.getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {

                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, PrivilegeException {
                    //判断用户调用的是什么方法
                    String methodName = method.getName();
                    System.out.println(methodName);

                    //得到用户调用的真实方法,注意参数!!!
                    Method method1 = t.getClass().getMethod(methodName,method.getParameterTypes());

                    //查看方法上有没有注解
                    permission permis = method1.getAnnotation(permission.class);

                    //如果注解为空,那么表示该方法并不需要权限,直接调用方法即可
                    if (permis == null) {
                        return method.invoke(t, args);
                    }

                    //如果注解不为空,得到注解上的权限
                    String privilege = permis.value();

                    //设置权限【后面通过它来判断用户的权限有没有自己】
                    Privilege p = new Privilege();
                    p.setName(privilege);

                    //到这里的时候,已经是需要权限了,那么判断用户是否登陆了
                    if (user == null) {

                        //这里抛出的异常是代理对象抛出的,sun公司会自动转换成运行期异常抛出,于是在Servlet上我们根据getCause()来判断是不是该异常,从而做出相对应的提示。
                        throw new PrivilegeException("对不起请先登陆");
                    }

                    //执行到这里用户已经登陆了,判断用户有没有权限
                    Method m = t.getClass().getMethod("findUserPrivilege", String.class);
                    List<Privilege> list = (List<Privilege>) m.invoke(t, user.getId());

                    //看下权限集合中有没有包含方法需要的权限。使用contains方法,在Privilege对象中需要重写hashCode和equals()
                    if (!list.contains(p)) {
                        //这里抛出的异常是代理对象抛出的,sun公司会自动转换成运行期异常抛出,于是在Servlet上我们根据getCause()来判断是不是该异常,从而做出相对应的提示。
                        throw new PrivilegeException("您没有权限,请联系管理员!");
                    }

                    //执行到这里的时候,已经有权限了,所以可以放行了
                    return method.invoke(t, args);
                }
            });

        } catch (Exception e) {
            new RuntimeException(e);
        }
        return null;
    }
}

PrivilegeExcetption

当用户没有登陆或者没有权限的时候,我们应该给用户一些友好的提示….于是我们自定义了PrivilegeException


public class PrivilegeException extends Exception {

    public PrivilegeException() {
        super();
    }

    public PrivilegeException(String message) {
        super(message);
    }

    public PrivilegeException(String message, Throwable cause) {
        super(message, cause);
    }

    public PrivilegeException(Throwable cause) {
        super(cause);
    }
}

我们继承的是Exception,通过方法名抛出去。但是我们是通过代理对象调用方法的,于是sun公司的策略就是把它们转换成运行期异常抛出去。

因此,我们就在Servlet上得到异常,再给出友好的提示。。


效果:

  • 没有登陆的时候:

这里写图片描述

  • 登陆了,但是没有相对应的权限的时候

这里写图片描述

  • 登陆了,并且有权限

这里写图片描述

要点总结

该权限控制是十分优雅的,只要我在Service层中添加一个注解…那么当web层调用该方法的时候就需要判断用户有没有该权限….

  1. 外界调用Service层的方法是代理调用invoke()方法,我们在invoke()方法可以对其进行增强!
  2. invoke()方法内部就是在查询调用该方法上有没有注解,如果没有注解,就可以直接调用。如果有注解,那么就得到注解的信息,判断该用户有没有权限来访问这个方法
  3. 在反射具体方法的时候,必须记得要给出相对应的参数!
  4. 在invoke()方法抛出的编译时期异常,java会自动转换成运行期异常进行抛出…
  5. 使用contains()方法时,就要重写该对象的hashCode()和equals()
ABB机器人C#二次开发实战:从通信打通到数据读写的落地指南(附完整工程) 最近在做自动化产线升级项目时,遇到一个核心需求:用C#上位机实时读取ABB机器人的关节角度、IO信号,同时下发运动指令和参数配置。翻遍全网,要么是Robot Studio的基础操作教程,要么是C++/VC++的老旧案例,C#相关的实操内容要么只给片段代码,要么跳过通信配置、权限设置等关键步骤,导致刚上手时踩了无数坑——连接超时、数据读不到、写入无响应,甚至误触发机器人安全保护。 阅读详情

相关推荐

雷电模拟器+Google Play服务配置全指南:从安装到定位问题解决

本文详细介绍了雷电模拟器配置Google Play服务的全流程,包括版本选择、组件安装、定位服务调试及网络问题排查。针对安卓开发者的常见挑战,提供从基础到高级的解决方案,帮助优化测试环境稳定性与定位精度。

weixin_30399821的博客 1236

【Java简单实现图书管理系统】

简单实现图书管理系统

lsh0414的博客 4272

Comsol超声空化气泡仿真入门:从零搭建模型到网格划分的完整流程

本文详细介绍了使用Comsol进行超声空化气泡仿真的完整流程,从物理基础理解到模型搭建、网格划分及求解器设置。通过具体步骤和示例代码,帮助初学者和工程师快速掌握这一关键技术,应用于医疗设备和工业清洗等领域。

weixin_29289821的博客 165

java web 订单_javaweb图书商城设计之订单模块(5)

这篇文章是针对javaweb图书商城中订单模块的研究,1、创建相关类domain:OrderOrderItemdao:OrderDaoservice:OrderServiceweb.servlete:OrderServlet/*** 订单条目类*/public class OrderItem {private String iid;private int count;// 数量private do...

weixin_35414437的博客 748

智能车竞赛飞檐走壁组赛道制作全攻略:从电磁线铺设到立体元素搭建

本文提供了智能车竞赛飞檐走壁组赛道制作的完整指南。从电磁线选材、电流控制与精准铺设等基础入手,详细解析了垂直墙面、圆筒、跷跷板等核心立体元素的构建技巧与过渡处理。重点分享了确保赛道稳定、符合规则且便于调试的实战经验,帮助参赛队伍搭建可靠的立体赛道,为车模算法调试奠定坚实基础。

weixin_29292535的博客 1280

基于FSL的DTI数据预处理流程

最近在学习处理DTI数据,总结了一份应用FSL做DTI数据预处理的流程与大家交流交流。如果有错误的地方欢迎大家指正!        我用的数据是Philips的数据,如果是GE或者西门子的数据可能会有所不同。   原始数据:包括3DT1数据和高分辨率DTI数据,均是dicom格式。 工具:MRICRON和FSL,所有的命令均在Linux的终端中运行。   1.格式转换:将后缀名为dcm

zaza_zaza的博客 2万+

Java-实现图书管理系统

java实现图书管理系统,要求两种运行方式1.管理员 2.使用者 管理员功能:查找图书,新增图书,删除图书,显示图书,退出系统 使用者功能:查找图书,借阅图书,归还图书,退出系统

chara9885的博客 3180

昇腾Ascend310b部署deepseek-r1-7b的学习记录

9.鲲鹏服务器+昇腾卡(Atlas 300I pro)搭建DeepSeek-R1-Distill-Qwen-7B(自己存档详细版)5.如何使用昇腾Ascend 300I Pro 310P芯片 单卡运行DeepSeek-R1-Distilled-Qwen-7B。6.鲲鹏服务器+昇腾卡(Atlas 300I pro)搭建DeepSeek-R1-Distill-Qwen-7B。7.鲲鹏+昇腾部署DeepSeek-R1-Distill-Qwen-32B+Open-webui。

maken 2373

Java实现图书管理系统(超详细解析)

纯Java实现简易图书管理(超详细)

guyongl的博客 8860

Doris + Iceberg 实现高效数据湖分层:架构解析与最佳实践

本文深入解析了如何利用Doris与Iceberg构建高效的数据湖冷热分层架构。通过将高频访问的热数据存储在Doris中以实现毫秒级查询,同时将历史冷数据归档至低成本的Iceberg存储,该方案在保障查询性能的同时显著降低了总体拥有成本。文章详细阐述了从架构设计、自动化迁移到统一查询的最佳实践,为应对海量数据下的成本与性能平衡提供了实战指南。

weixin_29207533的博客 135

5G NR上行控制信道PUCCH

一、PUCCH概述 PUCCH用于承载上行控制信息,相比LTE,NR PUCCH支持5种不同的格式,按照时域上所占用的符号数量可以分为短格式和长格式两种,如下表所示,短格式占用1-2个符号,可以承载1-2bit信息,长格式占用4-14个符号,可承载大于2bit的信息。NR引入短格式PUCCH的目的是可以缩短HARQ-ACK反馈的时延,长格式仍然是考虑到持续时间长可以保证覆盖。 NR中,考虑到系...

一个关于5G NR的博客^^ 3万+

编写Java程序,模拟网上商城购物,当用户选好物品提交订单时,每笔订单会自动生成一个唯一的订单编号。

查看本章节 查看作业目录 需求说明: 模拟网上商城购物,当用户选好物品提交订单时,每笔订单会自动生成一个唯一的订单编号。而部分电子商务网站在数据高峰期时,一毫秒可能需要处理近千笔的订单 现在简单模拟 5 个订单同时提交,生成唯一订单编号的场景。订单编号的生成规则是以毫秒为单位的当前时间+订单序号 例如,当前时间的毫秒数是 150000,那第 1 笔订单的编号就是 1500001,第 9 笔订单的编号就是 1500009 实现思路: 项目中创建订单类 Order(订单编号、订单金额、下单用户)

杨明金的博客 4724

代码接单:用 ComfyUI 搭建电商模特换装工作流(保姆级教程)

在闲鱼和小红书上,搜一下“AI 模特图”或者“服装换模特”,你会发现大量的接单需求。太贵:请个外模拍一套图,动辄几千块。太慢:寄样品、排期、拍摄、修图,半个月过去了。太卷:竞对都在上新,你还在等图。“给我一张你的衣服平铺图(或假人图),我 10 分钟给你生成真人上身图,一张只要 50 块。对于商家是省钱,对于你是纯利润。为什么不用 Midjourney?因为 MJ 抽卡不可控,无法保持衣服版型一致。只有 ComfyUI,才能做到精准控制,实现工业化量产。

BUG猿的博客 1779

【JavaWeb基础】图书管理系统【用户、购买、订单模块、添加权限】(修订版)

前言只有光头才能变强。文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y项目GitHub地址:htt...

3y 846

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

图书管理系统【JavaWeb:用户、购买、订单模块、添加权限】

用户模块 要登陆后才能购买,因此我们先写购买模块. 设计实体 private String id; private String username; private String password; private String email; private String cellphone; private String address; /...

weixin_34006965的博客 1349

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

javaweb 图书管理系统_【JavaWeb基础】图书管理系统【用户、购买、订单模块、添加权限】(修订版)...

前言只有光头才能变强。文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y项目GitHub地址:https://github.com/ZhongFuCheng3y/BookSystem用户模块要登陆后才能购买,因此我们先写购买模块.设计实体privateStringid;privateStringusername...

weixin_39804059的博客 223

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

手把手教你用 c++ 做 图书管理系统

图书管理系统设计题目要求思路分析各个模块的实现“书”类的创建管理模块的创建及实现管理权限添加图书查找图书修改图书删除图书销售模块的创建与实现统计模块的创建与实现创建简易登录界面文件的读取与存储 题目要求 1、问题描述 : 定义图书类,属性有:书名、出版社、ISBN 号、作者、库存量、价格等信息和相关的 对属性做操作的行为。 主要完成对图书的销售、统计和图书的简单管理。 2、功能要求 (1)销售功能: 购买书籍时,输入相应的 ISBN 号,并在书库中查找该书的相关信息。 如果有库存量,输入购买的册数,进行相应

Gettler的博客 5万+

JavaWeb图书管理系统完整版

JavaWeb图书管理系统完整版遵循MVC编程模式,基于Servlet、Bootstrap、MySQL等主要技术,实现了用户、管理员登录、用户注册、图书管理、图书类别管理、用户管理、借阅、归还书籍、借阅信息记录、退出登录等功能。项目涉及联表查询、图书-图书类别表拆分、session等技术。整个项目使用到14个JSP页面,功能相对完备,且功能操作方式符合逻辑、人性化。项目使用了Bootstrap前端ui框架,前端页面整洁美观。详情请参见“详细功能示例”部分。

m0_75223169的博客 7909

Javaweb基于ssm框架实现图书管理系统

前些天一直没有开学在家打王者,突然意识到有些荒废,于是做了一个基于ssm框架的图书管理系统,来做一下自我安慰吧。 先上效果图: 如上图所示,首页已经展示了主要的功能,这里我再细说一下吧: 首页: 首页的主要功能大部分都实现不了(首页主要用来展示一下小编的审美,前端是layui的组件拼接的,使用过layui的应该一眼就看出来了)前面纯属皮一下,这个管理系统需要身份的识别,需要先进行登录,在最右上角,点开登录有两种身份的登录方式:普通用户和管理员。 登录过后就会知道服务器关闭之前身份信息都会一直携带在.

归途 4289

JavaCore-OOP-4-图书管理系统(完善版V2)

图书管理系统完善版V2

起舞的日子 1143

JavaWeb图书管理系统【开发文档——bookEstore文档】

JavaWeb图书管理系统【bookEstore文档】

upward 3064

网络编程项目:图书管理系统

网络编程项目:图书管理系统

qq_57275300的博客 984
上一篇: 图书管理系统【JavaWeb:部署开发环境、解决分类、图书、前台页面模块】
下一篇: 【JavaWeb】图书管理系统【总结】
Java3y
Java3y 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 1万+粉丝 509原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值