소스 검색

基本增删改查

Luxnk 7 년 전
커밋
240bc7554e

+ 39 - 0
.gitignore

@@ -0,0 +1,39 @@
+
+# Created by https://www.gitignore.io/api/java,java-web
+
+### Java ###
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.war
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+### Java-Web ###
+## ignoring target file
+target/
+
+
+# End of https://www.gitignore.io/api/java,java-web
+
+# 自定义部分
+.idea/
+out/
+bin/
+lib_source/
+*.iml

+ 21 - 0
conf/ioc/dao.js

@@ -0,0 +1,21 @@
+var ioc = {
+    dataSource: {
+        type: "com.alibaba.druid.pool.DruidDataSource",
+        events: {
+            create: "init",
+            depose: "close"
+        },
+        fields: {
+            url: "jdbc:mysql://127.0.0.1:3306/luxnktask",
+            username: "root",
+            password: "",
+            testWhileIdle: true,
+            maxActive: 100,
+            maxWait: 15000
+        }
+    },
+    dao: {
+        type: "org.nutz.dao.impl.NutDao",
+        args: [{refer: "dataSource"}]
+    }
+}

+ 5 - 0
conf/log4j.properties

@@ -0,0 +1,5 @@
+log4j.rootLogger=debug,Console
+
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.layout=org.apache.log4j.PatternLayout
+log4j.appender.Console.layout.ConversionPattern=[%-5p] %d{HH:mm:ss.SSS} %l - %m%n

+ 0 - 0
conf/msg/zh-CN/user.properties


+ 14 - 0
src/xyz/luxnk/lproject/MainModule.java

@@ -0,0 +1,14 @@
+package xyz.luxnk.lproject;
+
+import org.nutz.mvc.annotation.*;
+import org.nutz.mvc.ioc.provider.ComboIocProvider;
+
+@SetupBy(value = MainSetup.class)
+@IocBy(type = ComboIocProvider.class, args = {"*js", "ioc/", "*anno", "xyz.luxnk.lproject", "*tx", "*async"})
+@Modules(scanPackage = true)
+@Ok("json:full")
+@Fail("jsp:jsp.500")
+@Localization(value = "msg/", defaultLocalizationKey = "zh-CN")
+public class MainModule {
+
+}

+ 38 - 0
src/xyz/luxnk/lproject/MainSetup.java

@@ -0,0 +1,38 @@
+package xyz.luxnk.lproject;
+
+import org.nutz.dao.Dao;
+import org.nutz.dao.util.Daos;
+import org.nutz.el.opt.custom.CustomMake;
+import org.nutz.ioc.Ioc;
+import org.nutz.mvc.NutConfig;
+import org.nutz.mvc.Setup;
+import xyz.luxnk.lproject.bean.UserInfo;
+import xyz.luxnk.lproject.util.SnowflakeIdWorker;
+
+import java.util.Date;
+
+public class MainSetup implements Setup {
+
+    @Override
+    public void init(NutConfig nc) {
+        Ioc ioc = nc.getIoc();
+        Dao dao = ioc.get(Dao.class);
+        Daos.createTablesInPackage(dao, "xyz.luxnk.lproject", false);
+        CustomMake.me().register("snowflake", ioc.get(SnowflakeIdWorker.class));
+
+        if (dao.count(UserInfo.class) == 0) {
+            UserInfo userInfo = new UserInfo();
+            userInfo.setUsername("Luxnk");
+            userInfo.setPassword("123456");
+            userInfo.setEmail("asd3115799@hotmail.com");
+            userInfo.setCreateTime(new Date());
+            userInfo.setUpdateTime(new Date());
+            dao.insert(userInfo);
+        }
+    }
+
+    @Override
+    public void destroy(NutConfig nc) {
+
+    }
+}

+ 87 - 0
src/xyz/luxnk/lproject/bean/UserInfo.java

@@ -0,0 +1,87 @@
+package xyz.luxnk.lproject.bean;
+
+import org.nutz.dao.entity.annotation.*;
+
+import java.util.Date;
+
+@Table("user_info")
+public class UserInfo {
+
+    @Name
+    @Prev(els = @EL("snowflake()"))
+    private String id;
+
+    @Column
+    private String username;
+
+    @Column
+    private String password;
+
+    @Column
+    private String salt;
+
+    @Column
+    private String email;
+
+    @Column("create_time")
+    private Date createTime;
+
+    @Column("update_time")
+    private Date updateTime;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getSalt() {
+        return salt;
+    }
+
+    public void setSalt(String salt) {
+        this.salt = salt;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+}

+ 159 - 0
src/xyz/luxnk/lproject/module/UserModule.java

@@ -0,0 +1,159 @@
+package xyz.luxnk.lproject.module;
+
+import org.nutz.dao.Cnd;
+import org.nutz.dao.Dao;
+import org.nutz.dao.QueryResult;
+import org.nutz.dao.pager.Pager;
+import org.nutz.ioc.loader.annotation.Inject;
+import org.nutz.ioc.loader.annotation.IocBean;
+import org.nutz.lang.Strings;
+import org.nutz.lang.util.NutMap;
+import org.nutz.mvc.annotation.*;
+import org.nutz.mvc.filter.CheckSession;
+import xyz.luxnk.lproject.bean.UserInfo;
+
+import javax.servlet.http.HttpSession;
+import java.util.Date;
+
+@IocBean    // 声明Ioc容器中的一个Bean
+@At("/user")    // 整个模块的路径前缀
+@Ok("json:{locked: 'password|salt', ignoreNull:true}")  // 忽略password和salt属性,忽略空属性的json输出
+@Fail("http:500")   // 抛出异常的话,就走500页面
+@Filters(@By(type = CheckSession.class, args = {"me", "/"}))    // 检查当前Session是否带me这个属性
+public class UserModule {
+
+    @Inject // 注入同名的一个ioc对象
+    protected Dao dao;
+
+    @At("/")
+    @Ok("jsp:jsp.user.list")    // 真实路径是 /WEB-INF/jsp/user/list.jsp
+    public void index() {}
+
+    /**
+     * 统计用户数
+     * @return
+     */
+    @At
+    public int count() {
+        return dao.count(UserInfo.class);
+    }
+
+    /**
+     * 用户登录
+     * @param username
+     * @param password
+     * @param session
+     * @return
+     */
+    @At
+    @Filters()  // 覆盖UserModule类的@Filters设置,因为登录可不能要求是个已经登陆的Session
+    public Object login(@Param("username")String username, @Param("password")String password, HttpSession session) {
+        UserInfo userInfo = dao.fetch(UserInfo.class, Cnd.where("username", "=", username).and("password", "=", password));
+        if (userInfo == null) {
+            return false;
+        } else {
+            session.setAttribute("me", userInfo.getId());
+            return true;
+        }
+    }
+
+    /**
+     * 用户登出
+     * @param session
+     */
+    @At
+    @Ok(">>:/") // 跟其他方法不同,这个方法完成后就跳转到首页了
+    public void logout(HttpSession session) {
+        session.invalidate();
+    }
+
+    /**
+     * 校验用户信息
+     * @param userInfo
+     * @param create
+     * @return
+     */
+    protected String checkUser(UserInfo userInfo, boolean create) {
+        if (userInfo == null) {
+            return "空对象";
+        }
+        if (create) {
+            if (Strings.isBlank(userInfo.getUsername()) || Strings.isBlank(userInfo.getPassword()))
+                return "用户名/密码不能为空";
+        } else {
+            if (Strings.isBlank(userInfo.getPassword()))
+                return "密码不能为空";
+        }
+        String passwd = userInfo.getPassword().trim();
+        if (6 > passwd.length() || passwd.length() > 12) {
+            return "密码长度错误";
+        }
+        userInfo.setPassword(passwd);
+        if (create) {
+            int count = dao.count(UserInfo.class, Cnd.where("username", "=", userInfo.getUsername()));
+            if (count != 0) {
+                return "用户已经存在";
+            }
+        } else {
+            if (Strings.isBlank(userInfo.getId())) {
+                return "用户Id非法";
+            }
+        }
+        if (userInfo.getUsername() != null) {
+            userInfo.setUsername(userInfo.getUsername().trim());
+        }
+        return null;
+    }
+
+    /**
+     * 新增用户
+     * @param userInfo
+     * @return
+     */
+    @At
+    public Object add(@Param("..")UserInfo userInfo) {  // 两个点号是表示按对象属性一一设置
+        NutMap re = new NutMap();
+        String msg = checkUser(userInfo, true);
+        if (msg != null) {
+            return re.setv("ok", false).setv("msg", msg);
+        }
+        userInfo.setCreateTime(new Date());
+        userInfo.setUpdateTime(new Date());
+        userInfo = dao.insert(userInfo);
+        return re.setv("ok", true).setv("data", userInfo);
+    }
+
+    @At
+    public Object update(@Param("..")UserInfo userInfo) {
+       NutMap re = new NutMap();
+       String msg = checkUser(userInfo, false);
+       if (msg != null) {
+           return re.setv("ok", false).setv("msg", msg);
+       }
+       userInfo.setUsername(null);  // 不允许更新用户名
+       userInfo.setCreateTime(null);    // 不允许更新创建时间
+       userInfo.setUpdateTime(new Date());  // 设置正确的更新时间
+       dao.updateIgnoreNull(userInfo);  // 真正更新的其实只有password和salt
+       return re.setv("ok", true);
+    }
+
+    @At
+    public Object delete(@Param("id")int id, @Attr("me")int me) {
+        if (me == id) {
+            return new NutMap().setv("ok", false).setv("msg", "不能删除当前用户!");
+        }
+        dao.delete(UserInfo.class, id); // 再严谨一些的话,需要判断结果是否为>0
+        return new NutMap().setv("ok", true);
+    }
+
+    @At
+    public Object query(@Param("name")String name, @Param("..")Pager pager) {
+        Cnd cnd = Strings.isBlank(name)? null : Cnd.where("name", "like", "%" + name + "%");
+        QueryResult qr = new QueryResult();
+        qr.setList(dao.query(UserInfo.class, cnd, pager));
+        pager.setRecordCount(dao.count(UserInfo.class, cnd));
+        qr.setPager(pager);
+        return qr;  // 默认分页是第1页,每页20条
+    }
+
+}

+ 154 - 0
src/xyz/luxnk/lproject/util/SnowflakeIdWorker.java

@@ -0,0 +1,154 @@
+package xyz.luxnk.lproject.util;
+
+import org.nutz.el.opt.RunMethod;
+import org.nutz.ioc.loader.annotation.IocBean;
+
+import java.util.List;
+
+/**
+ * Twitter_Snowflake<br>
+ * SnowFlake的结构如下(每部分用-分开):<br>
+ * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>
+ * 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br>
+ * 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)
+ * 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>
+ * 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId<br>
+ * 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号<br>
+ * 加起来刚好64位,为一个Long型。<br>
+ * SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。
+ */
+@IocBean
+public class SnowflakeIdWorker implements RunMethod {
+
+    // ==============================Fields===========================================
+    /** 开始时间截 (2015-01-01) */
+    private final long twepoch = 1420041600000L;
+
+    /** 机器id所占的位数 */
+    private final long workerIdBits = 5L;
+
+    /** 数据标识id所占的位数 */
+    private final long datacenterIdBits = 5L;
+
+    /** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
+    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
+
+    /** 支持的最大数据标识id,结果是31 */
+    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
+
+    /** 序列在id中占的位数 */
+    private final long sequenceBits = 12L;
+
+    /** 机器ID向左移12位 */
+    private final long workerIdShift = sequenceBits;
+
+    /** 数据标识id向左移17位(12+5) */
+    private final long datacenterIdShift = sequenceBits + workerIdBits;
+
+    /** 时间截向左移22位(5+5+12) */
+    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
+
+    /** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */
+    private final long sequenceMask = -1L ^ (-1L << sequenceBits);
+
+    /** 工作机器ID(0~31) */
+    private long workerId = 0;
+
+    /** 数据中心ID(0~31) */
+    private long datacenterId = 0;
+
+    /** 毫秒内序列(0~4095) */
+    private long sequence = 0L;
+
+    /** 上次生成ID的时间截 */
+    private long lastTimestamp = -1L;
+
+    //==============================Constructors=====================================
+    /**
+     * 构造函数
+     * @param workerId 工作ID (0~31)
+     * @param datacenterId 数据中心ID (0~31)
+     */
+    /*public SnowflakeIdWorker(long workerId, long datacenterId) {
+        if (workerId > maxWorkerId || workerId < 0) {
+            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
+        }
+        if (datacenterId > maxDatacenterId || datacenterId < 0) {
+            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
+        }
+        this.workerId = workerId;
+        this.datacenterId = datacenterId;
+    }*/
+
+    // ==============================Methods==========================================
+    /**
+     * 获得下一个ID (该方法是线程安全的)
+     * @return SnowflakeId
+     */
+    public synchronized long nextId() {
+        long timestamp = timeGen();
+
+        //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
+        if (timestamp < lastTimestamp) {
+            throw new RuntimeException(
+                    String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
+        }
+
+        //如果是同一时间生成的,则进行毫秒内序列
+        if (lastTimestamp == timestamp) {
+            sequence = (sequence + 1) & sequenceMask;
+            //毫秒内序列溢出
+            if (sequence == 0) {
+                //阻塞到下一个毫秒,获得新的时间戳
+                timestamp = tilNextMillis(lastTimestamp);
+            }
+        }
+        //时间戳改变,毫秒内序列重置
+        else {
+            sequence = 0L;
+        }
+
+        //上次生成ID的时间截
+        lastTimestamp = timestamp;
+
+        //移位并通过或运算拼到一起组成64位的ID
+        return ((timestamp - twepoch) << timestampLeftShift) //
+                | (datacenterId << datacenterIdShift) //
+                | (workerId << workerIdShift) //
+                | sequence;
+    }
+
+    /**
+     * 阻塞到下一个毫秒,直到获得新的时间戳
+     * @param lastTimestamp 上次生成ID的时间截
+     * @return 当前时间戳
+     */
+    protected long tilNextMillis(long lastTimestamp) {
+        long timestamp = timeGen();
+        while (timestamp <= lastTimestamp) {
+            timestamp = timeGen();
+        }
+        return timestamp;
+    }
+
+    /**
+     * 返回以毫秒为单位的当前时间
+     * @return 当前时间(毫秒)
+     */
+    protected long timeGen() {
+        return System.currentTimeMillis();
+    }
+
+    @Override
+    public Object run(List<Object> fetchParam) {
+        String id = nextId() + "";
+        System.out.println("看这里!!!!!!!!!!!!!!!!!!!! " + id);
+        return id;
+    }
+
+    @Override
+    public String fetchSelf() {
+        return "snowflake";
+    }
+}
+

+ 63 - 0
web/WEB-INF/jsp/500.jsp

@@ -0,0 +1,63 @@
+<%@ page import="org.nutz.mvc.Mvcs" %>
+<%@ page import="java.io.ByteArrayOutputStream" %>
+<%@ page import="java.io.PrintWriter" %>
+<%@ page import="org.nutz.lang.Strings" %>
+<%@ page import="java.util.Enumeration"%>
+<%--
+  Created by IntelliJ IDEA.
+  User: Administrator
+  Date: 2018/3/23 0023
+  Time: 10:10
+  To change this template use File | Settings | File Templates.
+--%>
+<%response.setStatus(500);%>
+<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" isErrorPage="true" trimDirectiveWhitespaces="true" session="false" %>
+<html>
+<head>
+    <title>出错啦</title>
+</head>
+<body>
+
+    <div>
+        <%
+            Throwable e = exception;
+            if (e == null) {
+                Object obj = request.getAttribute("obj");
+                if (obj != null && obj instanceof Throwable) {
+                    e = (Throwable)obj;
+                } else {
+                    if (Mvcs.getActionContext() != null) {
+                        e = Mvcs.getActionContext().getError();
+                    }
+                }
+            }
+        %>
+        <h2>请求的路径:<%=(request.getAttribute("javax.servlet.forward.request_uri") + (request.getQueryString() == null ? "" : "?" + request.getQueryString()))%></h2><p />
+        <%
+            if (Mvcs.getActionContext() != null) {
+        %>
+        <h2>请求的方法:<%=Mvcs.getActionContext().getMethod()%></h2><p />
+        <%
+            }
+            if (e != null) {
+        %>
+        <h2>异常堆栈如下:</h2><p />
+        <pre>
+            <code class="lang-java">
+                <%
+                    ByteArrayOutputStream bao = new ByteArrayOutputStream();
+                    PrintWriter pw = new PrintWriter(bao);
+
+                    e.printStackTrace(pw);
+                    pw.flush();
+                %>
+                <%=Strings.escapeHtml(new String(bao.toByteArray()))%>
+            </code>
+        </pre>
+        <%
+            }
+        %>
+    </div>
+
+</body>
+</html>

+ 123 - 0
web/WEB-INF/jsp/user/list.jsp

@@ -0,0 +1,123 @@
+<%--
+  Created by IntelliJ IDEA.
+  User: Administrator
+  Date: 2018/3/19 0019
+  Time: 16:41
+  To change this template use File | Settings | File Templates.
+--%>
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<html>
+<head>
+    <title>用户列表</title>
+    <script src="http://lib.sinaapp.com/js/jquery/2.0.3/jquery-2.0.3.min.js"></script>
+</head>
+<body>
+    <div>
+        <form action="#" id="user_query_form">
+            条件<input type="text" name="username" />
+            页数<input type="text" name="pageNumber" value="1" />
+            每页条数<input type="text" name="pageSize" value="10" />
+        </form>
+        <button type="button" id="user_query_btn">查询</button>
+        <p>---------------------------------------------------</p>
+        <p id="user_count"></p>
+        <div id="user_list"></div>
+    </div>
+    <div>
+        <p>---------------------------------------------------</p>
+    </div>
+    <div id="user_add">
+        <form action="#" id="user_add_form">
+            用户名<input type="text" name="username" />
+            密码<input type="password" name="password" />
+        </form>
+        <button type="button" id="user_add_btn">新增</button>
+    </div>
+
+    <script>
+        var pageNumber = 1;
+        var pageSize = 10;
+        var base = '<%=request.getAttribute("base")%>';
+        function user_reload() {
+            $.ajax({
+                url: base + '/user/query',
+                data: $('#user_query_form').serialize(),
+                dataType: 'json',
+                success: function (data) {
+                    console.log(data);
+                    $('#user_count').html('共' + data.pager.recordCount + '个用户,总计' + data.pager.pageCount + '页');
+                    var list_html = '';
+                    console.log(data.list);
+                    for (var i=0; i < data.list.length; i++) {
+                        var user = data.list[i];
+                        console.log(user);
+                        var tmp = '\n<p>' + user.id + ' ' + user.username
+                            + '<button onclick="user_update(' + user.id + ');">修改</button>'
+                            + '<button onclick="user_update(' + user.id + ');">删除</button>'
+                            + '</p>';
+                        list_html += tmp;
+                    }
+                    $('#user_list').html(list_html);
+                }
+            });
+        }
+        $(function () {
+            user_reload();
+            $('#user_query_btn').click(function () {
+               user_reload();
+            });
+            $('#user_add_btn').click(function () {
+                $.ajax({
+                    url: base + '/user/add',
+                    data: $('#user_add_form').serialize(),
+                    dataType: 'json',
+                    success: function (data) {
+                        if (data.ok) {
+                            user_reload();
+                            alert('添加成功');
+                        } else {
+                            alert(data.msg);
+                        }
+                    }
+                })
+            });
+        });
+        function user_update(userId) {
+            var passwd = prompt('请输入新的密码');
+            if (passwd) {
+                $.ajax({
+                    url: base + '/user/update',
+                    data: {'id': userId, 'password': passwd},
+                    dataType: 'json',
+                    success: function (data) {
+                        if (data.ok) {
+                            user_reload();
+                            alert('修改成功');
+                        } else {
+                            alert(data.msg);
+                        }
+                    }
+                });
+            }
+        }
+        function user_delete(userId) {
+            var s = prompt('请输入y确认删除');
+            if (s == 'y') {
+                $.ajax({
+                    url: base + '/user/dalete',
+                    data: {'id': userId},
+                    dataType: 'json',
+                    success: function (data) {
+                        if (data.ok) {
+                            user_reload();
+                            alert('删除成功');
+                        } else {
+                            alert(data.msg);
+                        }
+                    }
+                })
+            }
+        }
+    </script>
+</body>
+</html>

BIN
web/WEB-INF/lib/druid-1.1.9.jar


BIN
web/WEB-INF/lib/log4j-1.2.17.jar


BIN
web/WEB-INF/lib/mysql-connector-java-5.1.46.jar


BIN
web/WEB-INF/lib/nutz-1.r.65.jar


+ 33 - 0
web/WEB-INF/web.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
+		  http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+           version="2.5">
+
+    <welcome-file-list>
+        <welcome-file>index.html</welcome-file>
+        <welcome-file>index.jsp</welcome-file>
+    </welcome-file-list>
+    <error-page>
+        <error-code>500</error-code>
+        <location>/WEB-INF/jsp/500.jsp</location>
+    </error-page>
+
+    <filter>
+        <filter-name>nutz</filter-name>
+        <filter-class>org.nutz.mvc.NutFilter</filter-class>
+        <init-param>
+            <param-name>modules</param-name>
+            <param-value>xyz.luxnk.lproject.MainModule</param-value>
+        </init-param>
+    </filter>
+    <filter-mapping>
+        <filter-name>nutz</filter-name>
+        <url-pattern>/*</url-pattern>
+        <dispatcher>REQUEST</dispatcher>
+        <dispatcher>FORWARD</dispatcher>
+        <dispatcher>INCLUDE</dispatcher>
+    </filter-mapping>
+
+</web-app>

+ 60 - 0
web/index.jsp

@@ -0,0 +1,60 @@
+<%-- Created by IntelliJ IDEA. --%>
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<html>
+  <head>
+    <title>Nutz Demo</title>
+    <script src="js/jquery-1.8.3.min.js"></script>
+  </head>
+  <body>
+
+    <div id="login_div">
+      <form action="#" id="loginForm" method="post">
+        用户名 <input name="username" type="text" value="admin" />
+        密码 <input name="password" type="password" value="123456" />
+        <button type="button" id="login_button">提交</button>
+      </form>
+    </div>
+    <div id="user_info_div">
+      <p id="userInfo"></p>
+      <a href="${base}/user/logout">登出</a>
+    </div>
+
+    <script>
+      var me = '<%=session.getAttribute("me")%>';
+      var base = '${base}';
+      $(function () {
+          $('#login_button').click(function () {
+              console.log('尝试登录……');
+              $.ajax({
+                  url: base + '/user/login',
+                  type: 'post',
+                  data: $('#loginForm').serialize(),
+                  error: function (request) {
+                      alert('Connection error');
+                  },
+                  dataType: 'json',
+                  success: function (data) {
+                      alert(data);
+                      if (data == true) {
+                          alert('登录成功');
+                          location.reload();
+                      } else {
+                          alert('登录失败,请检查账号密码');
+                      }
+                  }
+              });
+              return false;
+          });
+          if (me != 'null') {
+              $('#login_div').hide();
+              $('#userInfo').html('您的Id是' + me);
+              $('#user_info_div').show();
+          } else {
+              $('#login_div').show();
+              $('#user_info_div').hide();
+          }
+      });
+    </script>
+
+  </body>
+</html>

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 2 - 0
web/js/jquery-1.8.3.min.js